2015-02-24 22 views
6

Tôi đã đọc về cách tài sản nguyên mẫu Javascript hoạt động cùng với thừa kế và sau đó bắt đầu xem xét thông qua mã Angular.js và đưa ra một số câu hỏi.Tại sao chỉ định Cái gì đó cho Something.prototype.constructor?

Trước hết, tôi đọc rằng thuộc tính mẫu thử trỏ đến một đối tượng có thuộc tính "hàm tạo" trỏ trở lại hàm ban đầu được sử dụng để tạo đối tượng. Vì vậy, ví dụ:

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

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

Nguyên mẫu cũng chứa bất kỳ các phương pháp khác hoặc tài sản đã được xác định trên nó bằng cách cho chúng tôi hoặc bằng ngôn ngữ Javascript chính nó, và đây là những chia sẻ của tất cả các trường của đối tượng. Nếu bạn muốn một đối tượng được gọi là Square để kế thừa từ Shape, bạn cần phải đặt mẫu thử Square bằng một mẫu mới của Shape vì thuộc tính [[prototype]] bên trong của Square.prototype được đặt thành giá trị đối tượng công khai của thuộc tính Shape.prototype .

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

Điều này có ý nghĩa với tôi.

Tuy nhiên, mã Angular.js mà tôi có câu hỏi về dường như có liên quan đến tất cả những điều này nhưng làm điều gì đó mà tôi không hiểu. Nó dường như không phải là đối phó với thừa kế vì vậy tôi có thể hiểu tại sao sẽ có sự khác biệt, nhưng tôi chỉ tò mò tại sao họ đã viết nó theo cách họ đã làm.

Trong phạm vi Angular.js, có một đối tượng HashMap và đối tượng Lexer, nhưng chúng được định nghĩa khác nhau nhưng có vẻ như được khởi tạo và sử dụng theo cùng một cách chính xác. Hàm tạo của Lexer được định nghĩa lần đầu tiên, và sau đó chúng đặt nguyên mẫu cho một đối tượng chứa các phương thức có thể được chia sẻ bởi tất cả các trường hợp của Lexer. Điều này tất cả đều có ý nghĩa. Những gì tôi không hiểu là lý do tại sao họ chỉ định thuộc tính "constructor" và thiết lập nó chỉ là "Lexer" khi chúng không cho HashMap bên dưới.

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) { ... } 
}; 

Sau đó, nếu bạn nhìn vào mã HashMap, chúng thực hiện tương tự ngoại trừ việc chúng không chỉ định thuộc tính hàm tạo. Tại sao điều này? Nó xuất hiện để làm việc chính xác như nhau, và tôi đã thử nghiệm rằng các nhà xây dựng vẫn được gọi.

// 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) { ... } 
}; 

Vì vậy, thuộc tính hàm tạo tùy chọn khi không có kế thừa, vì vậy có thể một người đã viết Lexer và một HashMap khác và một người đã quyết định chỉ định hàm tạo?

+0

xem thêm [Xác định nguyên mẫu Javascript] (http://stackoverflow.com/q/17474390/1048572) – Bergi

+0

@Bergi Cảm ơn, điều đó giúp ích. – Triad

Trả lời

8

Theo mặc định, mỗi mẫu thử đều có thuộc tính constructor đề cập đến chức năng mà nó "thuộc".

function A() { 
 
} 
 

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

Nếu bạn ghi đè lên một nguyên mẫu một cách trọn vẹn với một đối tượng đen hoặc với một số nguyên mẫu xây dựng khác, giá trị constructor này sẽ được xóa đi và bị bỏ lại không xác định hoặc với một số giá trị khác.

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

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

Thuộc tính prototype constructor là không cần thiết để cho các nhà xây dựng để hoạt động một cách chính xác, nhưng người ta thường sẽ phân công lại prototype.constructor trở lại giá trị ban đầu của nó để duy trì tính nhất quán, và đó là những gì bạn đang xem cho Lexer.

xem xét:

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

Người ta chỉ có thể suy đoán là tại sao điều này đã được bỏ ra cho HashMap. Tôi nghi ngờ nó đã được thực hiện cho bất kỳ lý do tốt và có thể chỉ là một giám sát.

+0

Cảm ơn bạn đã xóa thông tin đó. Tôi cảm thấy ngớ ngẩn khi không nhìn thấy điều đó, nhưng tôi đã nhìn nó khác đi trước đây bởi vì tôi bối rối vì sao họ đặt "constructor: Lexer" thay vì "constructor: new Lexer()", nhưng bây giờ tôi thấy tại sao điều đó không có ý nghĩa ở tất cả. Đó là SubConstructor.prototype = new Constructor() mà nên có "mới" từ khóa mà sau đó sẽ tự động định giá trị "SubConstructor.prototype.constructor" tài sản để "Constructor", đó là một kịch bản khác nhau từ một góc trên. – Triad

+1

@ Vô số Vâng, đúng vậy. Hãy nhớ rằng việc sử dụng 'SubConstructor.prototype = new Constructor()' để tạo ra các nguyên mẫu bây giờ là một thực hành lỗi thời. Ngày nay nó sẽ là 'SubConstructor.prototype = Object.create (Constructor.prototype);' – JLRishe

+0

Ah, rất tốt để biết, cảm ơn lần nữa. – Triad

Các vấn đề liên quan