Sự khác biệt đầu tiên có thể được tóm tắt là: this
đề cập đến Trường hợp của lớp. prototype
đề cập đến Định nghĩa .
Hãy nói rằng chúng ta có lớp sau:
var Flight = function ( number ) { this.number = number; };
Vì vậy, ở đây chúng tôi đang gắn this.number
vào mọi trường hợp của lớp, và nó có ý nghĩa bởi vì mỗi Flight
nên có số hiệu chuyến bay riêng của họ.
var flightOne = new Flight( "ABC" );
var flightTwo = new Flight( "XYZ" );
Ngược lại, prototype
định nghĩa một thuộc tính duy nhất có thể được truy cập bởi tất cả các trường hợp.
Bây giờ nếu chúng tôi muốn lấy số hiệu chuyến bay, chúng tôi chỉ cần viết đoạn mã sau và tất cả các phiên bản của chúng tôi sẽ nhận được Tài liệu tham khảo cho đối tượng mới được tạo mẫu này.
Flight.prototype.getNumber = function () { return this.number; };
Sự khác biệt thứ hai là về cách JavaScript tìm kiếm một thuộc tính của một đối tượng. Khi bạn đang tìm kiếm Object.whatever
, JavaScript sẽ tìm đến đối tượng Object chính (đối tượng mà mọi thứ khác được thừa hưởng từ đó) và ngay khi tìm thấy kết quả khớp, nó sẽ trả về hoặc gọi nó.
Nhưng điều đó chỉ xảy ra đối với các thuộc tính nguyên mẫu. Vì vậy, nếu bạn có một nơi nào đó ở các tầng cao hơn this.whatever
, JavaScript sẽ không coi đó là một trận đấu và sẽ tiếp tục tìm kiếm.
Chúng ta hãy xem nó xảy ra như thế nào trong thực tế.
Lưu ý đầu tiên rằng [hầu hết] mọi thứ đều là Đối tượng trong JavaScript. Thử đi:
typeof null
Bây giờ chúng ta hãy xem những gì bên trong một Object
(lưu ý Uppercase O
và .
cuối cùng). Trong Công cụ dành cho nhà phát triển của Google Chrome khi bạn nhập.
bạn sẽ nhận được danh sách các thuộc tính khả dụng bên trong đối tượng cụ thể đó.
Object.
Bây giờ làm điều tương tự cho Function
:
Function.
Bạn có thể nhận thấy name
phương pháp. Chỉ cần đi và bắn nó lên và xem điều gì sẽ xảy ra:
Object.name
Function.name
Bây giờ hãy tạo một hàm:
var myFunc = function () {};
Và hãy xem nếu chúng ta có name
phương pháp ở đây là tốt:
myFunc.name
Bạn sẽ nhận được một chuỗi rỗng, nhưng không sao. Bạn không nên nhận được Lỗi hoặc Ngoại lệ.
Bây giờ chúng ta hãy thêm một cái gì đó giống như thần Object
và xem liệu chúng ta có nhận được nó ở những nơi khác không?
Object.prototype.test = "Okay!";
Và ở đó bạn đi:
Object.prototype.test
Function.prototype.test
myFunc.prototype.test
Trong mọi trường hợp bạn nên xem "Okay!"
.
Về ưu và nhược điểm của từng phương pháp, bạn có thể coi việc tạo nguyên mẫu là một cách làm "hiệu quả hơn", vì nó giữ một tham chiếu trên mọi trường hợp thay vì sao chép toàn bộ thuộc tính trong mỗi đối tượng. Mặt khác, đây là một ví dụ về Khớp nối chặt chẽ , một điều không nên lớn cho đến khi bạn thực sự có thể biện minh cho lý do. this
là khá phức tạp vì nó liên quan đến bối cảnh. Bạn có thể tìm thấy rất nhiều tài nguyên tốt miễn phí trên internet.
Như đã nói, cả hai cách chỉ là công cụ ngôn ngữ và nó thực sự phụ thuộc vào bạn và vấn đề bạn đang cố gắng giải quyết để chọn ra cái gì phù hợp hơn.
Nếu bạn cần phải có một thuộc tính phù hợp với mọi thể hiện của một lớp, thì hãy sử dụng this
. Nếu bạn cần phải có một thuộc tính để hoạt động giống nhau trên mọi trường hợp, sau đó sử dụng prototype
.
Cập nhật
Về đoạn mã mẫu của bạn, cái đầu tiên là một ví dụ về Singleton , vì vậy nó có ý nghĩa khi sử dụng this
trong cơ thể đối tượng. Bạn cũng có thể cải thiện ví dụ của mình bằng cách biến nó thành mô-đun như thế này (và bạn không cần phải luôn luôn sử dụng this
).
/* Assuming it will run in a web browser */
(function (window) {
window.myApp = {
...
}
})( window );
/* And in other pages ... */
(function (myApp) {
myApp.Module = {
...
}
})( myApp );
/* And if you prefer Encapsulation */
(function (myApp) {
myApp.Module = {
"foo": "Foo",
"bar": function ( string ) {
return string;
},
return {
"foor": foo,
"bar": bar
}
}
})( myApp );
Đoạn mã thứ hai của bạn không có ý nghĩa nhiều như vậy bởi vì trước tiên bạn đang sử dụng this
và sau đó bạn đang cố gắng hack nó prototype
, điều này không hoạt động vìthis
được ưu tiên hơn prototype
. Tôi không chắc những mong đợi của bạn từ đoạn mã đó và cách nó hoạt động, nhưng tôi khuyên bạn nên cấu trúc lại nó.
Cập nhật
Để giải thích về this
việc được ưu tiênprototype
tôi có thể chỉ cho bạn một ví dụ và cho bạn biết làm thế nào để giải thích nó, nhưng tôi không có bất kỳ nguồn lực bên ngoài nào để sao lưu.
Ví dụ rất đơn giản:
var myClass = function () { this.foo = "Foo"; };
myClass.prototype.foo = "nice try!";
myClass.prototype.bar = "Bar";
var obj = new myClass;
obj.foo; // Still contains "Foo" ...
obj.bar; // Contains "Bar" as expected
Giải thích là, như chúng ta biết, this
có liên quan đến bối cảnh. Vì vậy, nó sẽ không tồn tại cho đến khi bối cảnh đã sẵn sàng. Khi bối cảnh đã sẵn sàng? Khi phiên bản mới đang được tạo! Bạn nên đoán phần còn lại bây giờ! Điều đó có nghĩa là mặc dù có một prototype
định nghĩa, nhưng this
có ý nghĩa hơn để được ưu tiên bởi vì đó là tất cả về trường hợp mới được tạo ra tại thời điểm đó.