2016-05-12 78 views
4

今天上午创建的对象采用超我碰到一个tweet from Šime Vidas来了,他提出在对象文本使用super以下可能性:用的Object.create

let A = { 
    run() { 
    console.log('A runs'); 
    } 
}; 

let B = { 
    run() { 
    super.run(); 
    } 
}; 

Object.setPrototypeOf(B, A); 

B.run(); // A runs 

这工作,并指派B.__proto__ = A;,而不是似乎工作在Firefox和Chrome中都是如此。

所以我想我可以做同样的Object.create

let A = { 
    run() { 
    console.log('A runs'); 
    } 
}; 

let B = Object.create(A); 
B.run = function() { super.run() }; 

不幸的是,这会导致两个Firefox的一个错误:

SyntaxError: use of super property accesses only valid within methods or eval code within methods

和Chrome:

Uncaught SyntaxError: 'super' keyword unexpected here

当我尝试将属性描述符对象传递给的第二个参数时,会发生同样的情况。

从语义上讲,它们看起来都和我一样,所以我不太清楚发生了什么(是因为对象字面量?)。

现在我想知道,这是准确定义的标准行为(spec参考赞赏)吗?是否有一些实现缺少Object.create,或者对象文字不起作用?

+0

好,对象'B'你的情况是' (好吧,我知道这个词不应该用在JS上下文中)'A'。所以'B.run();'和A.run();'?是一样的。 – Arg0n

+0

检查[此鸣叫](https://twitter.com/awbjs/status/730770661145088000)这意味着超级只能用于简短和定义方法。 –

+0

是的,我问他;) – nils

回答

4

艾伦夫斯 - 布洛克,在ES2015规范的编辑,还跟answer my question on twitter

这是什么错误?

super property references can only occurs in “concise methods” within a class def or obj lit http://tc39.github.io/ecma262/#sec-function-definitions-static-semantics-early-errors

在规范的这些部分,静态语义:前期差错,有四点,似乎是相关的:

  • 这是一个语法错误,如果FormalParameters包含超性质为真。
  • 如果FunctionBody包含SuperProperty为true,则它是一个语法错误。
  • 如果FormalParameters包含SuperCall,则它是一个语法错误。
  • 如果FunctionBody包含SuperCall,则它是一个语法错误。

因此,超级属性调用既不允许在函数参数中,也不允许在常规函数体中使用。因此我的问题。

为什么需要使用方法定义?

the reason is that super requires a back link from the method to its containing object. http://tc39.github.io/ecma262/#sec-runtime-semantics-definemethod

意义,如果我有一个方法,一个超级呼叫,我那方法分配给另一个变量,它仍然有工作:

let B = { 
    run() { 
    super.run(); 
    }, 
    walk() { 
    console.log(typeof this.run); 
    } 
}; 

var run = B.run; 
run(); // the 'super' binding still works, thanks to the internal MakeMethod 

var walk = B.walk; 
walk(); // 'undefined': the 'this' binding on the other hand is lost, as usual 

这在步骤7中指定部分定义方法的语义,其目前不用于常规的分配发生的对象:

  • 执行MakeMethod(闭合,对象)。
  • 这些语义在未来会发生变化吗?

    The back link is essential. Ways to dynamically set it were considered and could be again. Left out b/c error prone

    因此,这将是可能的,像.toMethod,它可以设置对象super引用,可以引入语言毕竟,使与Object.create可能我最初的例子。

    0

    我的意思是,你可以这样做:

    let A = { 
        run() { 
        console.log('A runs'); 
        } 
    }; 
    
    let B = { 
        run() { 
        super.run(); 
        } 
    }; 
    
    Object.setPrototypeOf(B, A); 
    
    let C = Object.create(B); 
    C.run(); //A runs 
    

    顺便说一句,这也失败:

    let A = { 
        run() { 
        console.log('A runs'); 
        } 
    }; 
    
    let B = { 
        run: function() { 
        super.run(); // 'super' keyword unexpected here 
        } 
    }; 
    
    Object.setPrototypeOf(B, A); 
    
    B.run(); 
    
    +1

    你的答案的第一部分似乎不相关,第二部分更有趣。也许它必须是一个方法定义,如下所示:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions – nils

    1

    你的答案涵盖了大部分。 super调用只能在方法中使用,因为方法与它们声明的对象紧密相关。这就是说,你最好的办法是做

    let B = { 
        __proto__: A, 
        run(){ 
         super.run(); 
        } 
    }; 
    

    以声明的方式创建具有A为原型而无需可能去优化呼叫Object.setPrototypeOf(B, A).

    +0

    谢谢澄清,我以某种方式假定这个概念也将是depotimizing。所以只要它发生在对象的最初定义中,它仍然被现代引擎优化了。 – nils

    +0

    据我所知,是的,但它确实需要一个支持'__proto__'的引擎,所以它在IE <= 10时不起作用。如果您需要支持ES5环境,您可以将https://www.npmjs.com/package/babel-plugin-proto-to-create移植到Babel 6(它是Babel 5)。 – loganfsmyth