2016-05-12 76 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