Câu hỏi JavaScript .prototype hoạt động như thế nào?


Tôi không phải là ngôn ngữ lập trình động, nhưng tôi đã viết phần mã JavaScript công bằng của mình. Tôi không bao giờ thực sự có được cái đầu của tôi xung quanh lập trình dựa trên nguyên mẫu này, có ai biết nó hoạt động như thế nào không?

var obj = new Object(); // not a functional object
obj.prototype.test = function() { alert('Hello?'); }; // this is wrong!

function MyObject() {} // a first class functional object
MyObject.prototype.test = function() { alert('OK'); } // OK

Tôi nhớ một cuộc thảo luận rất nhiều tôi đã có với mọi người một thời gian trở lại (Tôi không chính xác chắc chắn những gì tôi đang làm) nhưng khi tôi hiểu nó, không có khái niệm về một lớp học. Nó chỉ là một đối tượng, và các thể hiện của các đối tượng đó là bản sao của bản gốc, đúng không?

Nhưng mục đích chính xác của việc này là gì .prototype tài sản trong JavaScript? Làm thế nào nó liên quan đến các đối tượng instantiating?


Chỉnh sửa

Những trang trình bày thực sự đã giúp rất nhiều để hiểu chủ đề này.


1858
2018-02-21 12:31


gốc


John Resig có một vài trang trình bày về các nguyên mẫu chức năng hữu ích cho tôi khi nhìn vào chủ đề (bạn cũng có thể thay đổi mã và xem điều gì sẽ xảy ra ...) http://ejohn.org/apps/learn/#64 - John Foster
Tài liệu tham khảo tuyệt vời, vì mục đích giữ thông tin câu hỏi này có lẽ đặt một số nhận xét từ trang web của John về câu trả lời của bạn trong trường hợp trang web của anh ấy thay đổi theo cách liên kết của bạn không còn nữa. Dù bằng cách nào +1, đã giúp tôi. - Chris
+1 cho liên kết của bạn đến Trang trình bày JavaScript Ninja của John Resig # 64. Bắt đầu từ đó thực sự hữu ích và tôi cảm thấy mình hiểu nguyên mẫu một cách chính xác. - a paid nerd
Chúng ta có thực sự cần một đối tượng chức năng để áp dụng nguyên mẫu không? nếu có hơn lý do tại sao? - Anshul
Điều này có thể giúp bạn: webdeveasy.com/javascript-prototype - Naor


Các câu trả lời:


Mỗi đối tượng JavaScript có một thuộc tính nội bộ được gọi là [[Prototype]]. Nếu bạn tra cứu tài sản qua obj.propName hoặc là obj['propName'] và đối tượng không có thuộc tính như vậy - có thể được kiểm tra qua obj.hasOwnProperty('propName') - thời gian chạy tìm kiếm thuộc tính trong đối tượng được [[Prototype]] tham chiếu. Nếu đối tượng nguyên mẫu cũng không có thuộc tính như vậy, nguyên mẫu của nó được kiểm tra lần lượt, do đó đi bộ đối tượng gốc chuỗi nguyên mẫu cho đến khi tìm thấy kết quả phù hợp hoặc kết thúc của nó.

Một số triển khai JavaScript cho phép truy cập trực tiếp vào thuộc tính [[Prototype]], ví dụ: thông qua một thuộc tính không chuẩn có tên __proto__. Nói chung, nó chỉ có thể thiết lập nguyên mẫu của đối tượng trong khi tạo đối tượng: Nếu bạn tạo một đối tượng mới qua new Func(), thuộc tính [[Prototype]] của đối tượng sẽ được đặt thành đối tượng được tham chiếu bởi Func.prototype.

Điều này cho phép mô phỏng các lớp trong JavaScript, mặc dù hệ thống kế thừa của JavaScript là - như chúng ta đã thấy - nguyên mẫu và không dựa trên lớp:

Chỉ cần nghĩ về hàm xây dựng như là các lớp và các thuộc tính của nguyên mẫu (tức là của đối tượng được tham chiếu bởi hàm của hàm tạo prototype tài sản) là thành viên được chia sẻ, tức là các thành viên giống nhau cho mỗi cá thể. Trong các hệ thống dựa trên lớp, các phương thức được thực hiện theo cùng một cách cho mỗi cá thể, vì vậy các phương thức thường được thêm vào nguyên mẫu, trong khi các trường của đối tượng là một cá thể cụ thể và do đó được thêm vào chính đối tượng đó trong quá trình xây dựng.


927
2018-02-21 13:33



Vì vậy, tôi đang làm một cái gì đó sai bằng cách xác định các thuộc tính mới trên tài sản nguyên mẫu trong đoạn ngắn của tôi? - John Leidegren
Tôi nghĩ đây là ý nghĩa của việc có các đối tượng chức năng như công dân hạng nhất. - John Leidegren
Tôi ghét những thứ không chuẩn, đặc biệt là trong các ngôn ngữ lập trình, tại sao thậm chí còn có proto khi rõ ràng là không cần thiết? - John Leidegren
@ H1D: nếu Class.method không tìm thấy, thời gian chạy tìm kiếm Class.__proto__.method (hay đúng hơn Object.getPrototypeOf(Class).method trong ES5 tuân thủ) và không phải  Class.prototype.method - Christoph
lưu ý rằng việc sử dụng [[Prototype]] là cố ý - ECMA-262 bao quanh tên của các thuộc tính bên trong với các dấu ngoặc vuông kép - Christoph


Trong ngôn ngữ thực hiện kế thừa cổ điển như Java, C # hoặc C ++ bạn bắt đầu bằng cách tạo một lớp - kế hoạch chi tiết cho các đối tượng của bạn - và sau đó bạn có thể tạo các đối tượng mới từ lớp đó hoặc bạn có thể mở rộng lớp, định nghĩa một lớp mới bổ sung lớp gốc.

Trong JavaScript, trước tiên bạn tạo một đối tượng (không có khái niệm về lớp), sau đó bạn có thể tăng thêm đối tượng của riêng mình hoặc tạo các đối tượng mới từ nó. Nó không phải là khó khăn, nhưng một chút nước ngoài và khó để chuyển hóa cho ai đó sử dụng theo cách cổ điển.

Thí dụ:

//Define a functional object to hold persons in JavaScript
var Person = function(name) {
  this.name = name;
};

//Add dynamically to the already defined object a new getter
Person.prototype.getName = function() {
  return this.name;
};

//Create a new object of type Person
var john = new Person("John");

//Try the getter
alert(john.getName());

//If now I modify person, also John gets the updates
Person.prototype.sayMyName = function() {
  alert('Hello, my name is ' + this.getName());
};

//Call the new method on john
john.sayMyName();

Cho đến bây giờ tôi đã mở rộng đối tượng cơ sở, bây giờ tôi tạo một đối tượng khác và sau đó kế thừa từ Person.

//Create a new object of type Customer by defining its constructor. It's not 
//related to Person for now.
var Customer = function(name) {
    this.name = name;
};

//Now I link the objects and to do so, we link the prototype of Customer to 
//a new instance of Person. The prototype is the base that will be used to 
//construct all new instances and also, will modify dynamically all already 
//constructed objects because in JavaScript objects retain a pointer to the 
//prototype
Customer.prototype = new Person();     

//Now I can call the methods of Person on the Customer, let's try, first 
//I need to create a Customer.
var myCustomer = new Customer('Dream Inc.');
myCustomer.sayMyName();

//If I add new methods to Person, they will be added to Customer, but if I
//add new methods to Customer they won't be added to Person. Example:
Customer.prototype.setAmountDue = function(amountDue) {
    this.amountDue = amountDue;
};
Customer.prototype.getAmountDue = function() {
    return this.amountDue;
};

//Let's try:       
myCustomer.setAmountDue(2000);
alert(myCustomer.getAmountDue());

var Person = function (name) {
    this.name = name;
};
Person.prototype.getName = function () {
    return this.name;
};
var john = new Person("John");
alert(john.getName());
Person.prototype.sayMyName = function () {
    alert('Hello, my name is ' + this.getName());
};
john.sayMyName();
var Customer = function (name) {
    this.name = name;
};
Customer.prototype = new Person();

var myCustomer = new Customer('Dream Inc.');
myCustomer.sayMyName();
Customer.prototype.setAmountDue = function (amountDue) {
    this.amountDue = amountDue;
};
Customer.prototype.getAmountDue = function () {
    return this.amountDue;
};
myCustomer.setAmountDue(2000);
alert(myCustomer.getAmountDue());

Trong khi như đã nói, tôi không thể gọi setAmountDue (), getAmountDue () trên một Person.

//The following statement generates an error.
john.setAmountDue(1000);

1755
2018-01-24 03:42



Tôi nghĩ rằng các câu trả lời trên stackoverflow không chỉ thú vị với các poster ban đầu, mà còn cho một cộng đồng lớn của những người khác ẩn hoặc đến từ tìm kiếm. Và tôi đã là một trong số họ và tôi đã được hưởng lợi từ các bài đăng cũ. Tôi nghĩ rằng tôi có thể đóng góp cho các câu trả lời khác thêm một số ví dụ mã. Về câu hỏi của bạn: nếu bạn bỏ qua câu hỏi mới, nó không hoạt động. khi tôi gọi myCustomer.sayMyName () nó trả về "myCustomer.sayMyName không phải là một hàm". Cách dễ nhất là thử nghiệm với firebug và xem những gì sẽ xảy ra. - stivlo
Theo như tôi hiểu var Person = function (name) {...}; đang định nghĩa một hàm xây dựng có khả năng xây dựng các đối tượng Person. Vì vậy, không có đối tượng nào được nêu ra, chỉ có hàm constructor ẩn danh được gán cho Person. Đây là một lời giải thích rất tốt: helephant.com/2008/08/how-javascript-objects-work - stivlo
CẢNH BÁO: Câu trả lời này bỏ qua thực tế là hàm tạo lớp cha không được gọi trên cơ sở từng trường hợp. Lý do duy nhất nó hoạt động là vì anh ta đã làm điều tương tự (thiết lập tên) trong cả hàm con và hàm tạo cha. Để có giải thích chi tiết hơn về các lỗi thường gặp khi cố gắng kế thừa trong JavaScript (và giải pháp cuối cùng), vui lòng xem: bài đăng tràn ngăn xếp này - Aaren Cordova
Tôi nhận thấy rằng câu trả lời này cũng không đề cập rằng bằng cách sử dụng "new Person ()" làm nguyên mẫu, bạn thực sự thiết lập thuộc tính instance "name" của "Person" thành thuộc tính tĩnh của "Customer" (vì vậy tất cả khách hàng các cá thể sẽ có cùng thuộc tính). Trong khi đó là một ví dụ cơ bản tốt, KHÔNG LÀM R THNG. :) Tạo một hàm ẩn danh mới để hoạt động như một "cầu" bằng cách đặt nguyên mẫu của nó thành "Person.prototype", sau đó tạo một cá thể từ nó và đặt "Customer.prototype" thành cá thể ẩn danh đó thay thế. - James Wilkins
Về Customer.prototype = new Person(); dòng, MDN hiển thị ví dụ sử dụng Customer.prototype = Object.create(Person.prototype)và nói rằng 'Một lỗi phổ biến ở đây là sử dụng "Người mới ()". nguồn - Rafael Eyng


Tôi đóng một vai trò như một giáo viên JavaScript và khái niệm nguyên mẫu luôn luôn là một chủ đề gây tranh cãi để che đậy khi tôi dạy. Phải mất một thời gian để tôi nghĩ ra một phương pháp tốt để làm rõ khái niệm, và bây giờ trong bài viết này tôi sẽ cố gắng giải thích JavaScript hoạt động như thế nào.


Đây là một mô hình đối tượng dựa trên nguyên mẫu rất đơn giản sẽ được coi là mẫu trong khi giải thích, chưa có bình luận nào:

function Person(name){
    this.name = name;
}
Person.prototype.getName = function(){
    console.log(this.name);
}
var person = new Person("George");

Có một số điểm quan trọng mà chúng ta phải xem xét trước khi đi qua khái niệm nguyên mẫu.

1- Các hàm JavaScript thực sự hoạt động như thế nào:

Để thực hiện bước đầu tiên, chúng ta phải tìm ra cách các hàm JavaScript thực sự hoạt động như một lớp giống như hàm sử dụng this từ khóa trong đó hoặc chỉ là một hàm bình thường với các đối số của nó, những gì nó làm và những gì nó trả về.

Giả sử chúng ta muốn tạo Person mô hình đối tượng. nhưng trong bước này tôi sẽ cố gắng làm điều tương tự chính xác mà không cần sử dụng prototype và new từ khóa.

Vì vậy, trong bước này functions, objects và this từ khóa, là tất cả những gì chúng tôi có.

Câu hỏi đầu tiên sẽ là làm sao this từ khóa có thể hữu ích mà không cần sử dụng new từ khóa.

Vì vậy, để trả lời rằng chúng ta hãy nói rằng chúng ta có một đối tượng rỗng, và hai chức năng như:

var person = {};
function Person(name){  this.name = name;  }

function getName(){
    console.log(this.name);
}

và bây giờ không sử dụng new từ khóa cách chúng tôi có thể sử dụng các chức năng này. Vì vậy, JavaScript có 3 cách khác nhau để thực hiện điều đó:

a. cách đầu tiên chỉ là gọi hàm là hàm bình thường:

Person("George");
getName();//would print the "George" in the console

trong trường hợp này, đây sẽ là đối tượng ngữ cảnh hiện tại, thường là toàn cầu window đối tượng trong trình duyệt hoặc GLOBAL trong Node.js. Nó có nghĩa là chúng ta sẽ có, window.name trong trình duyệt hoặc GLOBAL.name trong Node.js, với "George" làm giá trị của nó.

b. Chúng ta có thể đính kèm chúng đến một đối tượng, như các thuộc tính của nó

- -Cách dễ nhất để làm điều này là sửa đổi trống person đối tượng, như:

person.Person = Person;
person.getName = getName;

theo cách này chúng ta có thể gọi chúng như:

person.Person("George");
person.getName();// -->"George"

và bây giờ là person đối tượng giống như:

Object {Person: function, getName: function, name: "George"}

- -Cách khác để đính kèm thuộc tính đối tượng đang sử dụng prototype của đối tượng đó có thể tìm thấy trong bất kỳ đối tượng JavaScript nào có tên __proto__và tôi đã cố gắng giải thích một chút về phần tóm tắt. Vì vậy, chúng tôi có thể nhận được kết quả tương tự bằng cách thực hiện:

person.__proto__.Person = Person;
person.__proto__.getName = getName;

Nhưng theo cách này, những gì chúng tôi đang thực hiện đang sửa đổi Object.prototype, bởi vì bất cứ khi nào chúng ta tạo một đối tượng JavaScript bằng cách sử dụng các chữ cái ({ ... }), nó được tạo dựa trên Object.prototype, có nghĩa là nó được gắn vào đối tượng mới được tạo thành một thuộc tính có tên __proto__ , vì vậy nếu chúng ta thay đổi nó, như chúng ta đã làm trên đoạn mã trước, tất cả các đối tượng JavaScript sẽ bị thay đổi, không phải là một thực hành tốt. Vì vậy, những gì có thể là thực hành tốt hơn bây giờ:

person.__proto__ = {
    Person: Person,
    getName: getName
};

và bây giờ các đối tượng khác đang trong hòa bình, nhưng nó vẫn không có vẻ là một thực hành tốt. Vì vậy, chúng tôi vẫn còn một giải pháp nữa, nhưng để sử dụng giải pháp này, chúng ta nên quay lại dòng mã đó person đối tượng đã được tạo (var person = {};) sau đó thay đổi nó như:

var propertiesObject = {
    Person: Person,
    getName: getName
};
var person = Object.create(propertiesObject);

những gì nó làm là tạo ra một JavaScript mới Object và đính kèm propertiesObject đến __proto__ thuộc tính. Vì vậy, để đảm bảo bạn có thể làm:

console.log(person.__proto__===propertiesObject); //true

Nhưng điểm khôn lanh ở đây là bạn có quyền truy cập vào tất cả các thuộc tính được xác định trong __proto__ ở cấp độ đầu tiên của person đối tượng (đọc phần tóm tắt để biết thêm chi tiết).


như bạn thấy bằng cách sử dụng bất kỳ cách nào trong hai cách này this chính xác sẽ trỏ đến person vật.

c. JavaScript có một cách khác để cung cấp hàm thisđang sử dụng gọi điện hoặc là ứng dụng để gọi hàm.

Phương thức apply () gọi một hàm với một giá trị đã cho và   đối số được cung cấp dưới dạng mảng (hoặc đối tượng giống mảng).

Phương thức call () gọi một hàm với một giá trị đã cho và   các đối số được cung cấp riêng lẻ.

theo cách này, đó là yêu thích của tôi, chúng tôi có thể dễ dàng gọi các chức năng của chúng tôi như:

Person.call(person, "George");

hoặc là

//apply is more useful when params count is not fixed
Person.apply(person, ["George"]);

getName.call(person);   
getName.apply(person);

3 phương pháp này là các bước quan trọng ban đầu để tìm ra chức năng .prototype.


2- Làm thế nào để new từ khóa hoạt động?

đây là bước thứ hai để hiểu .prototype function.this là những gì tôi sử dụng để mô phỏng quá trình:

function Person(name){  this.name = name;  }
my_person_prototype = { getName: function(){ console.log(this.name); } };

trong phần này, tôi sẽ cố gắng thực hiện tất cả các bước mà JavaScript thực hiện mà không cần sử dụng new từ khóa và prototype, khi bạn sử dụng new từ khóa. vì vậy khi chúng tôi làm new Person("George"), Person function là một hàm tạo, Đây là những gì JavaScript làm, từng cái một:

a. trước hết nó tạo ra một đối tượng rỗng, về cơ bản là một hash rỗng như sau:

var newObject = {};

b. bước tiếp theo mà JavaScript thực hiện là đính kèm tất cả các đối tượng nguyên mẫu cho đối tượng mới được tạo

chúng ta có my_person_prototype ở đây tương tự như đối tượng nguyên mẫu.

for(var key in my_person_prototype){
    newObject[key] = my_person_prototype[key];
}

Nó không phải là cách JavaScript thực sự gắn các thuộc tính được định nghĩa trong nguyên mẫu. Cách thực tế liên quan đến khái niệm chuỗi nguyên mẫu.


a. & b. Thay vì hai bước này, bạn có thể có kết quả chính xác bằng cách thực hiện:

var newObject = Object.create(my_person_prototype);
//here you can check out the __proto__ attribute
console.log(newObject.__proto__ === my_person_prototype); //true
//and also check if you have access to your desired properties
console.log(typeof newObject.getName);//"function"

bây giờ chúng ta có thể gọi getName chức năng của chúng tôi my_person_prototype:

newObject.getName();

c. sau đó nó đưa đối tượng đó cho hàm tạo,

chúng tôi có thể làm điều này với mẫu của chúng tôi như:

Person.call(newObject, "George");

hoặc là

Person.apply(newObject, ["George"]);

thì nhà xây dựng có thể làm bất cứ điều gì nó muốn, bởi vì điều này bên trong của constructor đó là đối tượng vừa được tạo.

bây giờ là kết quả cuối cùng trước khi mô phỏng các bước khác:     Đối tượng {name: "George"}


Tóm lược:

Về cơ bản, khi bạn sử dụng Mới từ khóa trên một hàm, bạn đang gọi hàm đó và hàm đó đóng vai trò như một hàm tạo, vì vậy khi bạn nói:

new FunctionName()

JavaScript trong nội bộ tạo một đối tượng, một băm rỗng và sau đó nó cung cấp cho đối tượng đó cho hàm tạo, sau đó hàm tạo có thể làm bất cứ điều gì nó muốn, bởi vì điều này bên trong của constructor đó là đối tượng vừa được tạo ra và sau đó nó mang lại cho bạn đối tượng đó tất nhiên nếu bạn không sử dụng câu lệnh return trong hàm của bạn hoặc nếu bạn đã đặt return undefined; ở cuối thân hàm của bạn.

Vì vậy, khi JavaScript đi tìm một thuộc tính trên một đối tượng, điều đầu tiên nó làm, là nó trông nó lên trên đối tượng đó. Và sau đó có một tài sản bí mật [[prototype]] mà chúng ta thường có nó __proto__ và thuộc tính đó là những gì JavaScript xem xét tiếp theo. Và khi nó nhìn qua __proto__, cho đến khi nó lại là một đối tượng JavaScript khác, nó có __proto__thuộc tính, nó đi lên và lên cho đến khi nó đến điểm tiếp theo __proto__ là null. Vấn đề là đối tượng duy nhất trong JavaScript __proto__ thuộc tính là null là Object.prototype vật:

console.log(Object.prototype.__proto__===null);//true

và đó là cách thức hoạt động của kế thừa trong JavaScript.

The prototype chain

Nói cách khác, khi bạn có một thuộc tính nguyên mẫu trên một hàm và bạn gọi một thuộc tính mới trên đó, sau khi JavaScript hoàn thành việc xem xét đối tượng mới được tạo cho các thuộc tính, nó sẽ xem xét hàm .prototype và cũng có thể là đối tượng này có nguyên mẫu bên trong riêng của nó. và vân vân.


163
2018-02-13 19:32



a) Xin đừng giải thích nguyên mẫu bằng cách sao chép các thuộc tính b) Thiết lập nội bộ [[nguyên mẫu]] xảy ra trước khi hàm xây dựng được áp dụng trên cá thể, vui lòng thay đổi thứ tự đó c) jQuery hoàn toàn ngoại lệ trong câu hỏi này - Bergi
@ Bergi: cảm ơn vì đã chỉ ra, tôi sẽ được đánh giá cao nếu bạn cho tôi biết nếu đó là ok bây giờ. - Mehran Hatami
Bạn có thể làm cho nó đơn giản? Bạn là đúng trên tất cả các điểm, nhưng những sinh viên đọc lời giải thích này có thể thực sự bối rối lần đầu tiên. nhận bất kỳ ví dụ đơn giản nào hơn và để mã giải thích chính nó hoặc thêm một loạt các nhận xét để làm rõ ý của bạn. - P.M
@ P.M: Cảm ơn phản hồi của bạn. Tôi đã cố gắng để làm cho nó đơn giản nhất có thể nhưng tôi nghĩ rằng bạn đang phải nó vẫn còn một số điểm mơ hồ. Vì vậy, tôi sẽ cố gắng sửa đổi nó và cũng có tính mô tả hơn. :) - Mehran Hatami
+1 cho hình minh họa ở cuối "cuốn sách" của bạn :) - sargas


prototype cho phép bạn tạo các lớp học. nếu bạn không sử dụng prototype thì nó trở thành tĩnh.

Đây là một ví dụ ngắn.

var obj = new Object();
obj.test = function() { alert('Hello?'); };

Trong trường hợp trên, bạn có kiểm tra cuộc gọi funcation tĩnh. Chức năng này chỉ có thể được truy cập bởi obj.test, nơi bạn có thể tưởng tượng obj là một lớp.

nơi như trong mã dưới đây

function obj()
{
}

obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();

Obj đã trở thành một lớp mà bây giờ có thể được khởi tạo. Nhiều trường hợp obj có thể tồn tại và tất cả chúng đều có test chức năng.

Trên đây là sự hiểu biết của tôi. Tôi làm cho nó thành một wiki cộng đồng, vì vậy mọi người có thể sửa tôi nếu tôi sai.


66
2017-11-07 09:48



-1: prototype là một thuộc tính của hàm xây dựng, không phải trường hợp, tức là mã của bạn sai! Có lẽ bạn có nghĩa là tài sản phi tiêu chuẩn __proto__ đối tượng, nhưng đó là một con thú hoàn toàn khác ... - Christoph
@Christoph - Cảm ơn bạn đã chỉ ra. Tôi đã cập nhật mã mẫu. - Ramesh
Đây là một câu trả lời hay, nhưng có nhiều câu trả lời hơn. - John Leidegren
Có nhiều hơn thế nữa ... Cộng với JavaScript không phải là một ngôn ngữ dựa trên lớp - nó đề cập đến sự kế thừa thông qua các nguyên mẫu, bạn cần phải trình bày những khác biệt chi tiết hơn! - James
Tôi nghĩ câu trả lời này là một chút sai lầm. - Armin Cifuentes


Sau khi đọc chủ đề này, tôi cảm thấy bối rối với JavaScript Prototype Chain, sau đó tôi tìm thấy những biểu đồ này

http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance *[[protytype]]* and <code>prototype</code> property of function objects

đó là biểu đồ rõ ràng để thể hiện sự thừa kế JavaScript của chuỗi Prototype

http://www.javascriptbank.com/javascript/article/JavaScript_Classical_Inheritance/

điều này chứa một ví dụ với mã và một số sơ đồ đẹp.

chuỗi nguyên mẫu cuối cùng rơi trở lại Object.prototype.

chuỗi nguyên mẫu có thể được mở rộng về mặt kỹ thuật miễn là bạn muốn, mỗi lần bằng cách thiết lập nguyên mẫu của lớp con bằng một đối tượng của lớp cha.

Hy vọng nó cũng hữu ích cho bạn để hiểu JavaScript Prototype Chain.


59
2018-05-26 20:40



Nó sẽ là tuyệt vời nếu bạn có thể cung cấp một tóm tắt ngắn về nội dung của các liên kết để câu trả lời này vẫn còn hữu ích khi các liên kết đã chết. - Nicktar
@ Nicktar, Cảm ơn bạn đã gợi ý, tôi đã thêm mô tả đơn giản bằng các liên kết này. - rockXrock
thats một biểu đồ rõ ràng? :) - Nuno_147
Một sơ đồ nói một ngàn chữ. Điều này rất hữu ích :) - Mark Robson
Bạn có thể giải thích những gì [[Prototype]] có nghĩa? - CodyBugstein


Bảy Koans nguyên mẫu

Khi Ciro San hạ xuống Mount Fire Fox sau khi thiền định sâu, tâm trí của ông rõ ràng và yên bình.

Tuy nhiên, bàn tay anh không ngừng nghỉ, và tự nó nắm lấy một chiếc bàn chải và ghi lại những ghi chú sau đây.


0) Hai thứ khác nhau có thể được gọi là "nguyên mẫu":

  • tài sản nguyên mẫu, như trong obj.prototype

  • tài sản nội bộ nguyên mẫu, được biểu thị là [[Prototype]]  trong ES5.

    Nó có thể được lấy thông qua ES5 Object.getPrototypeOf().

    Firefox làm cho nó có thể truy cập thông qua __proto__ tài sản như một phần mở rộng. ES6 hiện đã đề cập một số yêu cầu tùy chọn cho __proto__.


1) Những khái niệm đó tồn tại để trả lời câu hỏi:

Khi tôi làm obj.property, JS tìm kiếm ở đâu .property?

Trực giác, kế thừa cổ điển sẽ ảnh hưởng đến tra cứu tài sản.


2)

  • __proto__ được sử dụng cho dấu chấm . tra cứu thuộc tính như trong obj.property.
  • .prototype Là không phải được sử dụng để tra cứu trực tiếp, chỉ gián tiếp khi nó xác định __proto__ khi tạo đối tượng với new.

Thứ tự tra cứu là:

  • obj các thuộc tính được thêm với obj.p = ... hoặc là Object.defineProperty(obj, ...)
  • tính chất của obj.__proto__
  • tính chất của obj.__proto__.__proto__, v.v.
  • nếu một vài __proto__ Là null, trở về undefined.

Đây là cái gọi là chuỗi nguyên mẫu.

Bạn có thể tránh . tra cứu với obj.hasOwnProperty('key') và Object.getOwnPropertyNames(f)


3) Có hai cách chính để đặt obj.__proto__:

  • new:

    var F = function() {}
    var f = new F()
    

    sau đó new đã thiết lập:

    f.__proto__ === F.prototype
    

    Điều này là ở đâu .prototype được sử dụng.

  • Object.create:

     f = Object.create(proto)
    

    bộ:

    f.__proto__ === proto
    

4) Mật mã:

var F = function() {}
var f = new F()

Tương ứng với sơ đồ sau:

(Function)       (  F  )                                      (f)
 |  ^             | | ^                                        |
 |  |             | | |                                        |
 |  |             | | +-------------------------+              |
 |  |constructor  | |                           |              |
 |  |             | +--------------+            |              |
 |  |             |                |            |              |
 |  |             |                |            |              |
 |[[Prototype]]   |[[Prototype]]   |prototype   |constructor   |[[Prototype]]
 |  |             |                |            |              |
 |  |             |                |            |              |
 |  |             |                | +----------+              |
 |  |             |                | |                         |
 |  |             |                | | +-----------------------+
 |  |             |                | | |
 v  |             v                v | v
(Function.prototype)              (F.prototype)
 |                                 |
 |                                 |
 |[[Prototype]]                    |[[Prototype]]
 |                                 |
 |                                 |
 | +-------------------------------+
 | |
 v v
(Object.prototype)
 | | ^
 | | |
 | | +---------------------------+
 | |                             |
 | +--------------+              |
 |                |              |
 |                |              |
 |[[Prototype]]   |constructor   |prototype
 |                |              |
 |                |              |
 |                | -------------+
 |                | |
 v                v |
(null)           (Object)

Biểu đồ này hiển thị nhiều nút đối tượng được xác định trước ngôn ngữ: null, Object, Object.prototype, Function và Function.prototype. 2 dòng mã của chúng tôi chỉ được tạo f, F và F.prototype.


5)  .constructor thường đến từ F.prototype thông qua . tra cứu:

f.constructor === F
!f.hasOwnProperty('constructor')
Object.getPrototypeOf(f) === F.prototype
F.prototype.hasOwnProperty('constructor')
F.prototype.constructor === f.constructor

Khi chúng ta viết f.constructor, JavaScript thực hiện . tra cứu dưới dạng:

  • f không có .constructor
  • f.__proto__ === F.prototype có .constructor === F, cứ lấy đi

Kết quả f.constructor == F là trực giác chính xác, vì F được sử dụng để xây dựng f, ví dụ. thiết lập các trường, giống như trong các ngôn ngữ OOP cổ điển.


6) Cú pháp kế thừa cổ điển có thể đạt được bằng cách thao tác các chuỗi nguyên mẫu.

ES6 thêm class và extends từ khóa, đơn giản là đường cú pháp cho sự điên rồ của nguyên mẫu có thể có trước đó.

class C {
    constructor(i) {
        this.i = i
    }
    inc() {
        return this.i + 1
    }
}

class D extends C {
    constructor(i) {
        super(i)
    }
    inc2() {
        return this.i + 2
    }
}
// Inheritance syntax works as expected.
(new C(1)).inc() === 2
(new D(1)).inc() === 2
(new D(1)).inc2() === 3
// "Classes" are just function objects.
C.constructor === Function
C.__proto__ === Function.prototype
D.constructor === Function
// D is a function "indirectly" through the chain.
D.__proto__ === C
D.__proto__.__proto__ === Function.prototype
// "extends" sets up the prototype chain so that base class
// lookups will work as expected
var d = new D(1)
d.__proto__ === D.prototype
D.prototype.__proto__ === C.prototype
// This is what `d.inc` actually does.
d.__proto__.__proto__.inc === C.prototype.inc
// Class variables
// No ES6 syntax sugar apparently:
// http://stackoverflow.com/questions/22528967/es6-class-variable-alternatives
C.c = 1
C.c === 1
// Because `D.__proto__ === C`.
D.c === 1
// Nothing makes this work.
d.c === undefined

Giản đồ đơn giản mà không có tất cả các đối tượng được xác định trước:

      __proto__
(C)<---------------(D)         (d)
| |                |           |
| |                |           |
| |prototype       |prototype  |__proto__
| |                |           |
| |                |           |
| |                | +---------+
| |                | |
| |                | |
| |                v v
|__proto__        (D.prototype)
| |                |
| |                |
| |                |__proto__
| |                |
| |                |
| | +--------------+
| | |
| | |
| v v
| (C.prototype)--->(inc)
|
v
Function.prototype

57
2018-06-18 19:48



Tôi không biết nơi bạn có được điều này nhưng đây là câu trả lời rõ ràng nhất! - tomasb
@tomasb cảm ơn! "Tôi không biết bạn có được điều này ở đâu": sau khi tôi thấy một vài ngôn ngữ động, tôi nhận thấy điều quan trọng nhất về hệ thống lớp học của họ là cách . tra cứu các công trình (và bao nhiêu bản sao của dữ liệu được thực hiện). Vì vậy, tôi đặt ra để hiểu điểm đó. Phần còn lại là các bài đăng trên blog của Google + + thông dịch viên Js trong tầm tay. :) - Ciro Santilli 新疆改造中心 六四事件 法轮功
Câu trả lời này cho thấy sự hiểu biết thực sự và sâu sắc về khái niệm đó. Làm tốt lắm! - Nir Smadar
Tôi vẫn không hiểu tại sao g.constructor === Object bởi vì bạn nói rằng "4) Khi bạn làm f = new F, new cũng đặt f.constructor = F". Bạn có thể giải thích cho tôi nhiều hơn không? Dù sao đây là câu trả lời hay nhất tôi đang tìm kiếm. Cảm ơn bạn rất nhiều! - nguyenngoc101
@Now tất cả đều rõ ràng, tôi đã bình chọn cho câu trả lời của bạn. Cảm ơn vì đã giúp tôi. - nguyenngoc101


Mỗi đối tượng có một thuộc tính bên trong, [[Prototype]], liên kết nó với một đối tượng khác:

object [[Prototype]] -> anotherObject

Trong javascript truyền thống, đối tượng được liên kết là prototype tài sản của một hàm:

object [[Prototype]] -> aFunction.prototype

Một số môi trường phơi bày [[Prototype]] __proto__:

anObject.__proto__ === anotherObject

Bạn tạo liên kết [[Prototype]] khi tạo một đối tượng.

// (1) Object.create:
var object = Object.create(anotherObject)
// object.__proto__ = anotherObject

// (2) ES6 object initializer:
var object = { __proto__: anotherObject };
// object.__proto__ = anotherObject

// (3) Traditional JavaScript:
var object = new aFunction;
// object.__proto__ = aFunction.prototype

Vì vậy, các báo cáo này là tương đương:

var object = Object.create(Object.prototype);
var object = { __proto__: Object.prototype }; // ES6 only
var object = new Object;

A new tuyên bố không hiển thị mục tiêu liên kết (Object.prototype) chinh no; thay vào đó đích được ngụ ý bởi hàm tạo (Object).

Nhớ lại:

  • Mỗi đối tượng có một liên kết, [[Prototype]], đôi khi được hiển thị dưới dạng __proto__.
  • Mỗi hàm đều có prototype bất động sản.
  • Đối tượng được tạo bằng new được liên kết với prototype tài sản của nhà xây dựng của họ.
  • Nếu một hàm không bao giờ được sử dụng như một hàm tạo, thì nó prototype tài sản sẽ không được sử dụng.
  • Nếu bạn không cần một nhà xây dựng, hãy sử dụng Object.create thay vì new.

33
2018-02-21 12:41



+1 để làm nổi bật Object.create () - Jakob Sternberg
Bản sửa đổi 5 đã loại bỏ một số thông tin hữu ích, bao gồm thông tin về Object.create (). Xem phiên bản 4. - Palec
@Palec tôi nên thêm lại những gì? - sam
IMO ít nhất là liên kết đến Object.create() tài liệu, @sam. Liên kết đến __proto__ và Object.prototype sẽ là cải tiến tốt đẹp. Và tôi thích ví dụ của bạn về cách nguyên mẫu hoạt động với các nhà xây dựng và Object.create(), nhưng chúng có lẽ là phần dài và ít liên quan bạn muốn loại bỏ. - Palec
từ tất cả các thảo luận về những gì tôi nhận được (đến từ thừa kế cổ điển) nếu tôi tạo hàm dựng và cố gắng tạo cá thể của nó bằng toán tử mới, tôi sẽ chỉ nhận các phương thức và thuộc tính được gắn vào đối tượng proto, do đó cần phải đính kèm tất cả các phương thức và các thuộc tính để proto đối tượng nếu chúng ta muốn kế thừa, mi phải không? - blackHawk


Javascript không có thừa kế theo nghĩa thông thường, nhưng nó có chuỗi nguyên mẫu.

chuỗi nguyên mẫu

Nếu một thành viên của một đối tượng không thể được tìm thấy trong đối tượng, nó tìm kiếm nó trong chuỗi nguyên mẫu. Chuỗi bao gồm các đối tượng khác. Nguyên mẫu của một cá thể cụ thể có thể được truy cập bằng __proto__ biến. Mỗi đối tượng có một, vì không có sự khác biệt giữa các lớp và các cá thể trong javascript.

Ưu điểm của việc thêm một hàm / biến vào nguyên mẫu là nó phải nằm trong bộ nhớ chỉ một lần, không phải cho mọi cá thể.

Nó cũng hữu ích cho việc thừa kế, bởi vì chuỗi nguyên mẫu có thể bao gồm nhiều đối tượng khác.


23
2017-11-04 14:08



Hỗ trợ FF và Chrome proto, nhưng không phải IE hay Opera. - some
Georg, xin vui lòng làm rõ cho một noob - "không có sự khác biệt giữa các lớp học và các trường hợp trong javascript." - bạn có thể xây dựng được không? Cái này hoạt động ra sao? - Hamish Grubijan
từ tất cả các thảo luận về những gì tôi nhận được (đến từ thừa kế cổ điển) nếu tôi tạo hàm dựng và cố gắng tạo cá thể của nó bằng toán tử mới, tôi sẽ chỉ nhận các phương thức và thuộc tính được gắn vào đối tượng proto, do đó cần phải đính kèm tất cả các phương thức và các thuộc tính để proto đối tượng nếu chúng ta muốn kế thừa, mi phải không? - blackHawk


Bài viết này dài. Nhưng tôi chắc chắn nó sẽ xóa hầu hết các truy vấn của bạn về bản chất "nguyên mẫu" của JavaScript Thừa kế. Va thậm chi nhiêu hơn. Vui lòng đọc toàn bộ bài viết.

Về cơ bản, JavaScript có hai loại kiểu dữ liệu

  • Không đối tượng 
  • Các đối tượng

Không đối tượng

Sau đây là Không đối tượng loai du lieu

  • chuỗi
  • số (bao gồm NaN và Infinity)
  • giá trị boolean (đúng, sai) 
  • chưa xác định

Các kiểu dữ liệu này trả về sau khi bạn sử dụng loại nhà điều hành

loại  "chuỗi chữ" (hoặc biến chứa chuỗi chữ) === 'chuỗi'

loại  5 (hoặc bất kỳ chữ số hoặc biến số nào có chứa chữ số hoặc NaN hoặc Infynity) === 'con số'

loại  thật (hoặc là sai hoặc một biến chứa thật hoặc là sai) === 'boolean'

loại  chưa xác định (hoặc biến không xác định hoặc biến chứa chưa xác định) === 'chưa xác định'

Các chuỗi,con số và boolean các kiểu dữ liệu có thể được biểu diễn cả hai Các đối tượng và Không đối tượngKhi chúng được biểu diễn như là các đối tượng, typeof của chúng luôn là đối tượng === '. Chúng ta sẽ quay trở lại điều này khi chúng ta hiểu các kiểu dữ liệu đối tượng.

Các đối tượng

Các kiểu dữ liệu đối tượng có thể được chia thành hai loại

  1. Các đối tượng kiểu hàm
  2. Các đối tượng kiểu Non Function

Các Các đối tượng kiểu hàm là những người trả về chuỗi 'chức năng' với loại nhà điều hành. Tất cả các hàm do người dùng định nghĩa và tất cả các JavaScript được xây dựng trong các đối tượng có thể tạo các đối tượng mới bằng cách sử dụng toán tử mới thuộc thể loại này. Ví dụ:

  • Vật
  • Chuỗi 
  • Con số 
  • Boolean
  • Mảng 
  • Mảng đã nhập
  • RegExp
  • Chức năng 
  • Tất cả các đối tượng dựng sẵn khác có thể tạo đối tượng mới bằng cách sử dụng toán tử mới
  • chức năng  UserDefinedFunction() {/ * mã do người dùng xác định * /}

Vì thế, typeof (Object) === typeof (Chuỗi) === typeof (Số) === typeof (Boolean) === typeof (Mảng)  === typeof (RegExp) === typeof (Hàm)  === typeof (UserDefinedFunction) === 'chức năng'

Tất cả Các đối tượng kiểu hàm thực ra là các cá thể của đối tượng JavaScript được dựng sẵn Chức năng (bao gồm cả Chức năng đối tượng tức là nó được định nghĩa đệ quy). Nó giống như những vật thể này đã được xác định theo cách sau

var Object= new Function ([native code for object Object])
var String= new Function ([native code for object String])
var Number= new Function ([native code for object Number])
var Boolean= new Function ([native code for object Boolean])
var Array= new Function ([native code for object Array])
var RegExp= new Function ([native code for object RegExp])
var Function= new Function ([native code  for object Function])
var UserDefinedFunction= new Function ("user defined code")

Như đã đề cập, Các đối tượng kiểu hàm có thể tạo thêm các đối tượng mới bằng cách sử dụng toán tử mới. Ví dụ: một đối tượng thuộc loại Vật, Chuỗi, Con số, Boolean, Mảng, RegExp  Hoặc là UserDefinedFunction có thể được tạo bằng cách sử dụng

var a=new Object() or var a=Object() or var a={} //Create object of type Object
var a=new String() //Create object of type String
var a=new Number() //Create object of type Number
var a=new Boolean() //Create object of type Boolean
var a=new Array() or var a=Array() or var a=[]  //Create object of type Array
var a=new RegExp() or var a=RegExp() //Create object of type RegExp
var a=new UserDefinedFunction() 

Các đối tượng do đó tạo ra là tất cả Các đối tượng kiểu Non Function và trả lại loại==='vật'. Trong tất cả các trường hợp này, đối tượng "a" không thể tạo thêm đối tượng sử dụng toán tử mới. Vì vậy, sau đây là sai

var b=new a() //error. a is not typeof==='function'

Các đối tượng được xây dựng trong môn Toán Là loại==='vật'. Do đó một đối tượng Toán tử kiểu mới không thể được tạo bởi toán tử mới.

var b=new Math() //error. Math is not typeof==='function'

Cũng lưu ý rằng Vật,Mảng và RegExp chức năng có thể tạo đối tượng mới mà không cần sử dụng toán tử mới. Tuy nhiên, những người theo đuôi thì không.

var a=String() // Create a new Non Object string. returns a typeof==='string' 
var a=Number() // Create a new Non Object Number. returns a typeof==='number'
var a=Boolean() //Create a new Non Object Boolean. returns a typeof==='boolean'

Các hàm do người dùng định nghĩa là trường hợp đặc biệt.

var a=UserDefinedFunction() //may or may not create an object of type UserDefinedFunction() based on how it is defined.

Kể từ khi Các đối tượng kiểu hàm có thể tạo ra các đối tượng mới, chúng cũng được gọi là Constructors.

Mỗi Constructor / Chức năng (cho dù được xây dựng trong hoặc người dùng xác định) khi được xác định tự động có một thuộc tính được gọi là "nguyên mẫu" có giá trị theo mặc định được đặt làm đối tượng. Bản thân đối tượng này có một thuộc tính được gọi là "constructor" theo mặc định, tham chiếu trở lại Constructor / Chức năng .

Ví dụ khi chúng ta định nghĩa một hàm

function UserDefinedFunction()
{
}

tự động xảy ra sau

UserDefinedFunction.prototype={constructor:UserDefinedFunction}

Điều này thuộc tính "nguyên mẫu" chỉ hiện diện trong Các đối tượng kiểu hàm  (và không bao giờ Các đối tượng kiểu Non Function).

Điều này là bởi vì khi một đối tượng mới được tạo ra (sử dụng toán tử mới) nó thừa kế tất cả các thuộc tính và phương thức từ đối tượng nguyên mẫu hiện tại của hàm Constructor, tức là một  tài liệu tham khảo nội bộ  được tạo ra trong đối tượng mới được tạo tham chiếu đối tượng được tham chiếu bởi đối tượng nguyên mẫu hiện tại của hàm Constructor.

Điều này "tài liệu tham khảo nội bộ" được tạo trong đối tượng để tham chiếu các thuộc tính kế thừa được gọi là nguyên mẫu của đối tượng (tham chiếu đến đối tượng được tham chiếu bởi Constructor's "nguyên mẫu" tài sản nhưng khác với nó). Đối với bất kỳ đối tượng nào (chức năng hoặc chức năng không), điều này có thể được truy xuất bằng cách sử dụng Object.getPrototypeOf () phương pháp. Sử dụng phương pháp này người ta có thể theo dõi chuỗi nguyên mẫu của một đối tượng.

Cũng thế, mọi đối tượng được tạo (Loại chức năng hoặc là Loại không hoạt động) có một "constructor" thuộc tính được thừa hưởng từ đối tượng được tham chiếu bởi thuộc tính prototype của hàm Constructor. Theo mặc định, "constructor" tài sản tham khảo Hàm xây dựng đã tạo ra nó (nếu Hàm xây dựng mặc định "nguyên mẫu" không thay đổi).

Cho tất cả Các đối tượng kiểu hàm hàm hàm tạo luôn luôn function Hàm () {}

Dành cho Các đối tượng kiểu Non Function (ví dụ: Javascript được xây dựng trong đối tượng Math) hàm xây dựng là hàm tạo ra nó. Dành cho môn Toán đối tượng nó là function Object () {}.

Tất cả các khái niệm được giải thích ở trên có thể là một chút khó khăn để hiểu mà không cần bất kỳ mã hỗ trợ nào. Vui lòng xem qua dòng mã sau để hiểu khái niệm. Hãy thử thực hiện nó để hiểu rõ hơn.

function UserDefinedFunction()
{ 

} 

/* creating the above function automatically does the following as mentioned earlier

UserDefinedFunction.prototype={constructor:UserDefinedFunction}

*/


var newObj_1=new UserDefinedFunction()

alert(Object.getPrototypeOf(newObj_1)===UserDefinedFunction.prototype)  //Displays true

alert(newObj_1.constructor) //Displays function UserDefinedFunction

//Create a new property in UserDefinedFunction.prototype object

UserDefinedFunction.prototype.TestProperty="test"

alert(newObj_1.TestProperty) //Displays "test"

alert(Object.getPrototypeOf(newObj_1).TestProperty)// Displays "test"

//Create a new Object

var objA = {
        property1 : "Property1",
        constructor:Array

}


//assign a new object to UserDefinedFunction.prototype
UserDefinedFunction.prototype=objA

alert(Object.getPrototypeOf(newObj_1)===UserDefinedFunction.prototype)  //Displays false. The object referenced by UserDefinedFunction.prototype has changed

//The internal reference does not change
alert(newObj_1.constructor) // This shall still Display function UserDefinedFunction

alert(newObj_1.TestProperty) //This shall still Display "test" 

alert(Object.getPrototypeOf(newObj_1).TestProperty) //This shall still Display "test"


//Create another object of type UserDefinedFunction
var newObj_2= new UserDefinedFunction();

alert(Object.getPrototypeOf(newObj_2)===objA) //Displays true.

alert(newObj_2.constructor) //Displays function Array()

alert(newObj_2.property1) //Displays "Property1"

alert(Object.getPrototypeOf(newObj_2).property1) //Displays "Property1"

//Create a new property in objA
objA.property2="property2"

alert(objA.property2) //Displays "Property2"

alert(UserDefinedFunction.prototype.property2) //Displays "Property2"

alert(newObj_2.property2) // Displays Property2

alert(Object.getPrototypeOf(newObj_2).property2) //Displays  "Property2"

Chuỗi nguyên mẫu của mỗi đối tượng cuối cùng là dấu vết quay lại Object.prototype (bản thân nó không có bất kỳ đối tượng nguyên mẫu nào). Mã sau có thể được sử dụng để truy tìm chuỗi nguyên mẫu của một đối tượng

var o=Starting object;

do {
    alert(o + "\n" + Object.getOwnPropertyNames(o))

}while(o=Object.getPrototypeOf(o))

Chuỗi nguyên mẫu cho các đối tượng khác nhau hoạt động như sau.

  • Mỗi đối tượng Function (bao gồm cả đối tượng Function được xây dựng) -> Function.prototype -> Object.prototype -> null
  • Các đối tượng đơn giản (được tạo bởi đối tượng mới () hoặc {} bao gồm cả đối tượng Math được xây dựng) -> Object.prototype -> null
  • Đối tượng được tạo bằng mới hoặc Object.create -> Một hoặc nhiều chuỗi nguyên mẫu -> Object.prototype -> null

Để tạo một đối tượng mà không có bất kỳ mẫu thử nghiệm nào, hãy sử dụng các mục sau:

var o=Object.create(null)
alert(Object.getPrototypeOf(o)) //Displays null

Người ta có thể nghĩ rằng việc thiết lập thuộc tính prototype của Constructor thành null sẽ tạo một đối tượng với một nguyên mẫu null. Tuy nhiên trong các trường hợp như vậy, nguyên mẫu của đối tượng mới được tạo ra được đặt thành Object.prototype và hàm tạo của nó được đặt thành hàm Object. Điều này được thể hiện bằng mã sau

function UserDefinedFunction(){}
UserDefinedFunction.prototype=null// Can be set to any non object value (number,string,undefined etc.)

var o=new UserDefinedFunction()
alert(Object.getPrototypeOf(o)==Object.prototype)   //Displays true
alert(o.constructor)    //Displays Function Object

Sau phần tóm tắt của bài viết này

  • Có hai loại đối tượng Các loại chức năng và Các loại không hoạt động
  • Chỉ có Các đối tượng kiểu hàm có thể tạo đối tượng mới bằng cách sử dụng toán tử mới. Các đối tượng do đó được tạo ra là Loại không hoạt động các đối tượng. Các Các đối tượng kiểu Non Function không thể tạo thêm đối tượng bằng cách sử dụng toán tử mới.

  • Tất cả các Các đối tượng kiểu hàm theo mặc định có "nguyên mẫu" bất động sản. Điều này "nguyên mẫu" thuộc tính tham chiếu một đối tượng có "constructor" thuộc tính mặc định tham chiếu Đối tượng kiểu hàm chinh no.

  • Tất cả các đối tượng (Loại chức năng và Loại không hoạt động) có thuộc tính "constructor" theo mặc định tham chiếu Đối tượng kiểu hàm/Constructor đã tạo ra nó.

  • Mọi đối tượng được tạo nội bộ tham chiếu đối tượng được tham chiếu bởi "nguyên mẫu" tài sản của Constructor đã tạo ra nó. Đối tượng này được gọi là tạo nguyên mẫu của đối tượng (khác với loại đối tượng "nguyên mẫu" của đối tượng kiểu hàm mà nó tham chiếu). Bằng cách này, đối tượng được tạo có thể truy cập trực tiếp vào các phương thức và thuộc tính được định nghĩa trong đối tượng được tham chiếu bởi thuộc tính "nguyên mẫu" của Constructor (tại thời điểm tạo đối tượng).

  • An nguyên mẫu của đối tượng (và do đó các tên thuộc tính kế thừa của nó) có thể được lấy ra bằng cách sử dụng Object.getPrototypeOf ()   phương pháp. Trong thực tế, phương pháp này có thể được sử dụng để điều hướng toàn bộ chuỗi nguyên mẫu của đối tượng.

  • Chuỗi nguyên mẫu của mỗi đối tượng cuối cùng là dấu vết quay lại Object.prototype (Trừ khi đối tượng được tạo ra bằng cách sử dụng Object.create (null) trong trường hợp đối tượng không có nguyên mẫu).

  • typeof (new Array ()) === 'đối tượng' là do thiết kế của ngôn ngữ và không phải là một sai lầm như chỉ bởi Douglas Crockford 

  • Việc thiết lập thuộc tính prototype của Constructor thành null (hoặc không xác định, số, true, false, string) sẽ không tạo ra một đối tượng có một mẫu thử rỗng. Trong những trường hợp như vậy, nguyên mẫu của đối tượng mới được tạo ra được đặt thành Object.prototype và hàm tạo của nó được đặt thành hàm Object.

Hi vọng điêu nay co ich.


23
2017-07-03 21:44