2015-02-24 90 views
6

我正在閱讀關於Javascript原型屬性如何與繼承一起工作,然後開始查看Angular.js代碼並提出了一些問題。爲什麼將Something分配給Something.prototype.constructor?

首先,我讀到prototype屬性指向的對象具有「構造函數」屬性,該屬性指向用於創建對象的原始函數。因此,例如:

// This is the constructor 
function Shape() { 
    this.position = 1; 
} 

// The constructor points back to the original function we defined 
Shape.protoype.constructor == Shape; 

原型還包含已經由我們或JavaScript語言本身上定義的任何其他方法或屬性,而這些是由對象的所有實例共享。如果您想要一個名爲Square的對象從Shape繼承,您需要將Square的原型設置爲等於Shape的新實例,因爲Square.prototype的內部[[prototype]]屬性設置爲Shape.prototype屬性的公共對象值。

function Square() {} 
Square.prototype = new Shape(); 
var square = new Square(); 
square.position; // This will output 1 

這一切都對我有意義。

但是,我有一個問題的Angular.js代碼似乎與所有這些有關,但做了一些我不明白的事情。它似乎沒有處理繼承問題,所以我可以理解爲什麼會有差異,但我只是好奇他們爲什麼按照他們的方式編寫它。

在Angular.js中,有一個HashMap對象和一個Lexer對象,但是它們的定義有所不同,但似乎是以相同的方式實例化和使用。首先定義Lexer構造函數,然後將原型設置爲包含應該由Lexer的所有實例共享的方法的對象字面值。這一切都有道理。我不明白的是爲什麼他們指定「構造函數」屬性,並將它設置爲「Lexer」,而不是下面的HashMap。

var Lexer = function(options) { 
    this.options = options; 
}; 

// Notice they specify Lexer as the constructor even though they don't for HashMap below 
Lexer.prototype = { 
    constructor: Lexer, 
    lex: function(text) { ... }, 
    is: function(ch, chars) { ... }, 
    peek: function(i) { ... }, 
    isNumber: function(ch) { ... }, 
    isWhitespace: function(ch) { ... }, 
    isIdent: function(ch) { ... }, 
    isExpOperator: function(ch) { ... }, 
    throwError: function(error, start, end) { ... }, 
    readNumber: function() { ... }, 
    readIdent: function() { ... }, 
    readString: function(quote) { ... } 
}; 

然後,如果你看一下HashMap的代碼,他們這樣做只是它們不指定constructor屬性同樣的事情。爲什麼是這樣?它看起來工作完全一樣,我測試了構造函數仍然被調用。

// The HashMap Constructor 
function HashMap(array, isolatedUid) { 
    if (isolatedUid) { 
     var uid = 0; 
     this.nextUid = function() { 
      return ++uid; 
     }; 
    } 
    forEach(array, this.put, this); 
} 

HashMap.prototype = { 
    put: function(key, value) { ... }, 
    get: function(key) { ... }, 
    remove: function(key) { ... } 
}; 

原來是constructor屬性可選當沒有繼承,所以可能只是一個人寫的詞法分析器和另一個HashMap和一個決定指定構造?

+0

另請參閱[定義Javascript原型](http://stackoverflow.com/q/17474390/1048572) – Bergi 2015-02-24 20:30:55

+0

@Bergi謝謝,這有幫助。 – Triad 2015-02-24 22:27:34

回答

8

默認情況下,每個原型都具有constructor屬性,該屬性引用它「所屬」的函數。

function A() { 
 
} 
 

 
console.log(A.prototype.constructor === A); // true

如果覆蓋其全部與對象文本或與其他一些構建原型樣機,這constructor價值將得到擦乾,並留下未定義或與其他一些價值。

function A() { 
 
} 
 
A.prototype = { 
 
    greeting: "Hello!" 
 
}; 
 

 
console.log(A.prototype.constructor === A); // false

是不需要的原型constructor屬性,以便構造正常運行,但人們往往會爲了保持一致性,重新分配prototype.constructor回其初始值,這就是你正在尋找Lexer

考慮:

function A() { 
 
} 
 

 
function B() { 
 
} 
 

 
B.prototype = Object.create(A.prototype); 
 

 
var b = new B(); 
 

 
console.log(b.constructor === A); // true 
 
console.log(b.constructor === B); // false 
 

 
B.prototype.constructor = B; 
 

 
console.log(b.constructor === A); // false 
 
console.log(b.constructor === B); // true

人們只能猜測,爲什麼這被排除在外的HashMap。我懷疑這是出於任何理由而做的,可能只是一個疏忽。

+0

感謝您解決這個問題。我覺得有點愚蠢,因爲沒有看到這一點,但我之前以不同的眼光看待它,因爲我爲什麼把「構造函數:Lexer」而不是「構造函數:新Lexer()」弄糊塗了,但我現在明白了爲什麼沒有意義在所有。它是SubConstructor.prototype = new Constructor(),它應該有「new」關鍵字,然後會自動將「SubConstructor.prototype.constructor」屬性賦值給「Constructor」,這是與上面的Angular不同的場景。 – Triad 2015-02-24 20:25:15

+1

@Triad是的,這是正確的。請記住,使用'SubConstructor.prototype = new Constructor()'來創建原型現在是一個過時的做法。現在它會是'SubConstructor.prototype = Object.create(Constructor.prototype);' – JLRishe 2015-02-24 20:30:57

+0

啊,很高興知道,再次感謝。 – Triad 2015-02-24 22:20:31

相關問題