Tại sao việc sử dụng các nhà xây dựng không được khuyến khích khi tạo các nguyên mẫu?


10

Nền nhanh: Trong JavaScript, hàm tạo cho mỗi loại đối tượng có thuộc prototypetính. Đề prototypecập đến một đối tượng mà mỗi đối tượng được xây dựng sử dụng làm bước tiếp theo trong chuỗi nguyên mẫu của nó. Khi bạn muốn một loại vốn có từ loại khác, bạn có thể đặt prototypeloại con thành một thể hiện mới của loại cha.

Ví dụ:

var Parent = function() { /* constructor business */ }
Parent.prototype.parentProp = "some parent property";

var Child = function() { /* constructor business */ }
Child.prototype = /*** !! Some prototype object goes here !! ***/

Câu hỏi của tôi hỏi về mã nào sẽ đi vào Some prototype object goes herevị trí "" trong đoạn mã trên. Bản năng đầu tiên của tôi là xây dựng một thể hiện của cha mẹ (tức là new Parent()), nhưng trong một nhận xét cho câu trả lời trên Đây có phải là cách an toàn để sao chép nguyên mẫu của một đối tượng sang một đối tượng khác không? , một người dùng viết:

Không, không sử dụng new bar()cho các đối tượng nguyên mẫu!

(... Đó là một ý kiến ​​tôi đã thấy trong nhiều câu trả lời và bình luận của SO, nhưng đây là ví dụ duy nhất tôi có trong tay vào lúc này.)

Tùy chọn khác là sử dụng Object.create(Parent.prototype)như Child.prototype. Theo tôi biết, điều này cũng tạo ra một thể hiện mới Parent, nhưng nó không chạy hàm Parenttạo.

Ai đó có thể giải thích tại sao nên chạy hàm constructor khi tạo đối tượng nguyên mẫu từ kiểu cha không? Có một số vấn đề kỹ thuật quan trọng phát sinh (có thể với nhiều cấp độ thừa kế)? Hoặc một mô hình như vậy có phải là sự lạm dụng của các nhà xây dựng xung đột với một số thực tiễn tốt nhất về nguyên mẫu (ví dụ: chạy công cụ xây dựng khi tạo một nguyên mẫu vi phạm một số mối quan tâm)?

Câu trả lời:


5

Bởi vì đó là một chức năng không cần phải gọi. newkhông khác với một cuộc gọi chức năng thông thường trong Javascript.

Một constructor có thể làm nhiều hơn chỉ đơn giản là thiết lập các trường. Chẳng hạn, nếu nó xác nhận dữ liệu đến, thì bạn sẽ gây ra lỗi xác thực khi bạn chỉ đơn giản là cố gắng thiết lập chuỗi thừa kế.

Và bạn không cần Object.create, điều này là đủ:

function objectCreate( proto ) {
    function T(){}
    T.prototype = proto;
    return new T();
}

Nhưng đó chính xác Object.createlà cách thực hiện.
Casey Chu

@CaseyChu hoàn toàn không. Và tôi đã đề cập đến nó bởi vì trong bài đăng được liên kết, ai đó đã nói " Object.createkhông hoạt động trong IE8" - đó chỉ là nhận xét vô ích khi bạn có thể triển khai nó cho trường hợp sử dụng này trong 2 giây trên bất kỳ trình duyệt nào.
Esailija

2

Bây giờ sự hiểu biết của tôi đã mở rộng ra một chút, tôi muốn xây dựng câu trả lời của Esailija bằng một ví dụ cụ thể:

Một mối quan tâm cụ thể là một hàm tạo có thể đặt các thuộc tính đặc thù. Do đó, nếu bạn sử dụng một đối tượng nguyên mẫu được tạo bằng new, tất cả các thể hiện con của bạn có thể chia sẻ một thuộc tính cụ thể được xác định bởi hàm tạo từ nguyên mẫu.

Ví dụ: giả sử Parentmỗi trường hợp có một thuộc tính duy nhất idđược đặt là thời gian xây dựng:

var Parent = function() { this.id = Math.random(); }
Parent.prototype.parentProp = "some parent property";

var Child = function() { /* constructor business */ }
Child.prototype = new Parent();

Điều này sẽ khiến tất cả các Child trường hợp chia sẻ một thuộc tính nguyên mẫu duy nhất idđược kế thừa từ một và chỉ một new Parent()đối tượng được sử dụng như Child.prototype.

Một cách tiếp cận tốt hơn cho trường hợp này là sử dụng Object.createvà gọi trực tiếp hàm tạo của cha mẹ (nếu cần) bên trong hàm tạo con:

var Parent = function() { this.id = Math.random(); }
Parent.prototype.parentProp = "some parent property";

var Child = function() {
    // run `this` through the Parent constructor function
    Parent.apply(this, arguments);
}
Child.prototype = Object.create(Parent.prototype);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.