2015-05-28 60 views
10

我來到了包含這些行瞭解原型對象的創建與「的Object.create()」而不是「新」關鍵字

var data = function() { 
    function Metadata() { /*some initialization here*/ } 

    Metadata.prototype = Object.create(Backend.prototype); 
    Metadata.prototype.constructor = Metadata; 

    return Metadata; 
} 

我很難理解什麼是真正回事,以及如何將代碼使用返回的對象。如果我理解正確的話,現在data將是應該這樣

var d = new data() 

被初始化的對象,但我不明白以下行,爲什麼Object.create()使用new關鍵字來代替:

Metadata.prototype = Object.create(Backend.prototype); 
Metadata.prototype.constructor = Metadata; 

他們做什麼?他們有必要嗎? Object.createnew之間的區別是什麼?

回答

5

JavaScript是一種基於原型的語言。 這意味着它不像其他語言那樣使用關鍵字。相反,JavaScript使用函數作爲類。
在您的示例數據變量可以被同化到

var Data = function() { ... }

要創建這個類的一個實例,我們使用關鍵字指定類型的對象的結果到一個變量。

var data = new Data()

由於ECMA腳本6我們可以使用實例化方法Object.create()創造具有指定原型對象和屬性的外行對象。它需要將這個對象作爲新創建對象的原型。 (這也拷貝構造函數)

所以下面的線是一種方法,使元數據擴展後端對象,並保持自己的構造:

// Metadata extends Backend 
Metadata.prototype = Object.create(Backend.prototype); 
Metadata.prototype.constructor = Metadata; 

但是這個代碼不完全等同於Metadata.prototype = new Backend();。看到這個例子:

//Base class 
var Backend = function(){ this.publicProperty='SomeValue'; } 

//Extension class 1 
var Metadata1 = function() { } 
Metadata1.prototype = Object.create(Backend.prototype); 
Metadata1.prototype.constructor = Metadata1; 

//Extension class 2 
var Metadata2 = function() { } 
Metadata2.prototype = new Backend(); 


/* 
* Then the results are different (see code snippet at the end of this post) 
*/ 
//result1 = 'undefined' 
var data1 = new Metadata1(); 
var result1 = data1.publicProperty; 

//result2 = 'SomeValue' 
var data2 = new Metadata2(); 
var result2 = data2.publicProperty; 

其實都是非常相似,主要區別是new關鍵字實際運行構造函數代碼,而Object.create將不會執行代碼。

另外一個區別是,使用Object.create可以創建一個不會從任何東西繼承的對象(Object.create(null))。
如果你Metadata.prototype = null而新創建的對象將從Object.prototype


注意繼承:在一些較老的瀏覽器(IE8及以下),可以使用該等效代碼Object.create

Object.create = function(o){ 
    function F(){} 
    F.prototype=o; 
    return new F(); 
} 

以下是顯示兩種方法之間差異的工作代碼片段

//Base class 
 
var Backend = function(){ this.publicProperty='SomeValue'; } 
 

 
//Extension class 1 
 
var Metadata1 = function() { } 
 
Metadata1.prototype = Object.create(Backend.prototype); 
 
Metadata1.prototype.constructor = Metadata1; 
 

 
//Extension class 2 
 
var Metadata2 = function() { } 
 
Metadata2.prototype = new Backend(); 
 

 

 
//result: 'undefined' 
 
var data1 = new Metadata1(); 
 
$("#result1").text("result1: " + (typeof data1.publicProperty=='undefined' ? 'undefined' : data1.publicProperty)); 
 

 
//result: 'SomeValue' 
 
var data2 = new Metadata2(); 
 
$("#result2").text("result2: " + (typeof data2.publicProperty=='undefined' ? 'undefined' : data2.publicProperty));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<div id="result1"></div> 
 
<div id="result2"></div>

+1

謝謝。這非常令人困惑,我非常高興** ES6繼承語義(「擴展」,構造函數,「超級」)更容易理解。 –

5

這兩條線是Metadata延伸Backend的原型方式。

JavaScript中的類被定義爲函數。如果您在某個功能上定義了prototype,則可以使用new關鍵字(或Object.create)創建該類的一個實例。原型上的函數/屬性將位於您創建的類的新實例上。

在上面的代碼,Metadata.prototype被設置爲的Backend一個實例,因此Metadata.prototype將繼承調用上Backend.prototype的方法/屬性。

你可以在Inheritance and the prototype chain找到更多。

+0

是什麼'Metadata.prototype =的Object.create(Backend.prototype)之間的差值;'和'Metadata.prototype =新的後端()'? –

+2

當你使用Object.create時,構造函數不會被調用。所以如果你只想擴展'Backend'的原型,那麼'Object.create'是有道理的。 – wjohnsto

3

在JavaScript中沒有任何類,而是我們可以使用關鍵字new來調用構造函數來創建新對象,因此我們將獲得與類和實例相同的行爲。

而這兩條線來表示繼承關係,並作出Metadata延伸Backend,在該行:

Metadata.prototype = Object.create(Backend.prototype); 

我們定義的Metadata原型,對象應該是新創建的原型目的。

雖然在這一行:

Metadata.prototype.constructor = Metadata; 

我們定義將被用來創建Metadata新實例Metadata構造。

和繼承可以這樣測試:

var meta = new Metadata(); 

console.log('Is meta an instance of Metadata? ' + (meta instanceof Metadata)); // true 
console.log('Is meta an instance of Backend? ' + (meta instanceof Backend)); // true 

,你可以找到更多關於它在這裏的Object.create() documentaion另一個例子。

+0

'後端的meta實例'也應該是'true'。 – Leo

+0

@Leo Well指出,當然是,我錯過了,我編輯了我的答案,謝謝。 –

2

Object.create是一個ES6方法,它以給定的對象爲原型創建一個對象。

Metadata.prototype = Object.create(Backend.prototype); 

所以上面的線是指Metadata繼承Backend所有屬性和方法。這是ES6前以某種方式類似於以下行:

Metadata.prototype = new Backend(); 

然而,Metadata還繼承Backendconstructor屬性:

var metaData = new Metadata(); 
metaData.constructor; // function Backend() 

這看起來奇怪,因爲metaData實際上是與Metadata構造,所以我們修復它像這:

Metadata.prototype.constructor = Metadata; 

var metaData = new Metadata(); 
metaData.constructor; // function Metadata() 

請注意,這並不混亂instanceof操作:

metaData instanceof Metadata // true 
metaData instanceof Backend // true 
相關問題