Hãy nhớ rằng, các đối tượng mới có thể được tạo bằng hàm constructor, như new F().

Nếu F.prototypelà một đối tượng, thì toán tửnew sử dụng nó để tạo mới đối tượng[[Prototype]]

Xin lưu ý:

JavaScript có sự kế thừa nguyên mẫu ngay từ đầu. Đó là một trong những tính năng cốt lõi của ngôn ngữ.

Nhưng thời xưa, không có quyền truy cập trực tiếp vào nó. Điều duy nhất hoạt động đáng tin cậy là một thuộc tính"prototype" của hàm tạo, được mô tả trong chương này. Vì vậy, có nhiều kịch bản vẫn sử dụng nó.

Xin lưu ý rằng F.prototypeở đây có nghĩa là một thuộc tính thường xuyên có tên "prototype"trên đối tượngF. Nghe có vẻ tương tự như thuật ngữ Nguyên mẫu, nhưng ở đây chúng thực sự có nghĩa là một thuộc tính thông thường với tên này.

Đây là ví dụ:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

let animal = {
  eats: true
};

function Rabbit(name) {
  this.name = name;
}

Rabbit.prototype = animal;

let rabbit = new Rabbit("White Rabbit"); //  rabbit.__proto__ == animal

alert( rabbit.eats ); // true

Đặt Rabbit.prototype = animalnghĩa đen là: “Khi một new Rabbitđược tạo, gán [[Prototype]]của nó cho animal“.

Đó là hình ảnh kết quả:

Trên hình, "prototype"là một mũi tên nằm ngang, có nghĩa là một thuộc tính thông thường và [[Prototype]]là chiều dọc, có nghĩa là sự kế thừa rabbittừ animal.F.prototypechỉ được sử dụng tại thời điểm new F

thuộc tínhF.prototype chỉ được sử dụng khi new Fđược gọi, nó gán cho đối tượng mới[[Prototype]] .

Nếu, sau khi tạo, thuộc tínhF.prototype thay đổi ( F.prototype = <another object>), thì các đối tượng mới được tạo bởi new Fsẽ có một đối tượng khác là [[Prototype]], nhưng các đối tượng đã tồn tại giữ nguyên đối tượng cũ.

1. F.prototype Mặc định, thuộc tính constructor

Mọi hàm đều có thuộc tính "prototype" ngay cả khi chúng ta không cung cấp nó.

Mặc định "prototype"là một đối tượng có thuộc tính duy nhất constructortrỏ lại chính hàm đó.

Như thế này:

function Rabbit() {}

/* default prototype
Rabbit.prototype = { constructor: Rabbit };
*/

Chúng ta có thể kiểm tra nó:

function Rabbit() {}
// by default:
// Rabbit.prototype = { constructor: Rabbit }

alert( Rabbit.prototype.constructor == Rabbit ); // true

Đương nhiên, nếu chúng ta không làm gì, thuộc tính constructor có sẵn cho tất cả Rabbit thông qua [[Prototype]]:

function Rabbit() {}
// by default:
// Rabbit.prototype = { constructor: Rabbit }

let rabbit = new Rabbit(); // inherits from {constructor: Rabbit}

alert(rabbit.constructor == Rabbit); // true (from prototype)

Chúng ta có thể sử dụng thuộc tính constructorđể tạo một đối tượng mới bằng cách sử dụng cùng một hàm tạo như đối tượng hiện có.

Giống như ở đây:

function Rabbit(name) {
  this.name = name;
  alert(name);
}

let rabbit = new Rabbit("White Rabbit");

let rabbit2 = new rabbit.constructor("Black Rabbit");

Thật tiện lợi khi chúng ta có một đối tượng, không biết constructor nào đã được sử dụng cho nó (ví dụ: nó đến từ thư viện của bên thứ 3) và chúng ta cần tạo một đối tượng khác cùng loại.

Nhưng có lẽ điều quan trọng nhất "constructor"

Bản thân JavaScript không đảm bảo đúng giá trị"constructor".

Vâng, nó tồn tại trong "prototype"mặc định cho các hàm, nhưng đó là tất cả. Điều gì xảy ra với nó sau này – hoàn toàn thuộc về chúng ta.

Cụ thể, nếu chúng ta thay thế toàn bộ nguyên mẫu mặc định, thì sẽ không có "constructor"trong đó.

Ví dụ:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

function Rabbit() {}
Rabbit.prototype = {
  jumps: true
};

let rabbit = new Rabbit();
alert(rabbit.constructor === Rabbit); // false

Vì vậy, để giữ quyền, "constructor"chúng ta có thể chọn thêm / xóa các thuộc tính về "prototype"mặc định thay vì ghi đè toàn bộ:

function Rabbit() {}

// Not overwrite Rabbit.prototype totally
// just add to it
Rabbit.prototype.jumps = true
// the default Rabbit.prototype.constructor is preserved

Hoặc, cách khác, tạo lại thuộc tínhconstructor theo cách thủ công:

Rabbit.prototype = {
  jumps: true,
  constructor: Rabbit
};

// now constructor is also correct, because we added it

2. Tóm lược

Trong chương này, chúng ta đã mô tả ngắn gọn cách đặt[[Prototype]] cho các đối tượng được tạo thông qua hàm tạo. Sau đó, chúng ta sẽ thấy các mẫu lập trình nâng cao hơn dựa vào nó.

Mọi thứ khá đơn giản, chỉ cần một vài ghi chú để làm cho mọi thứ rõ ràng:

  • Thuộc tính F.prototype (không nhầm nó với [[Prototype]]) đặt [[Prototype]] của các đối tượng mới khi F() mới được gọi.
  • Giá trị của F.prototype phải là một đối tượng hoặc null
  • Thuộc tính “nguyên mẫu” chỉ có hiệu ứng đặc biệt như vậy khi được đặt trên hàm xây dựng(constructor) và được gọi với hàm mới.

Trên các đối tượng thông thường, nguyên mẫu không có gì đặc biệt:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

let user = {
  name: "John",
  prototype: "Bla-bla" // no magic at all
};

Theo mặc định, tất cả các hàm đều có F.prototype = {constructor: F}, vì vậy chúng ta có thể lấy hàm tạo(constructor) của một đối tượng bằng cách truy cập thuộc tính “constructor” của nó.

Full series tự học Javascript từ cơ bản tới nâng cao tại đây nha.

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!