Câu trả lời:
Tính kế thừa của Javascript dựa trên nguyên mẫu, vì vậy bạn mở rộng nguyên mẫu của các đối tượng như Ngày tháng, Toán học và thậm chí là các nguyên mẫu tùy chỉnh của riêng bạn.
Date.prototype.lol = function() {
alert('hi');
};
( new Date ).lol() // alert message
Trong đoạn mã trên, tôi xác định một phương thức cho tất cả các đối tượng Ngày (những đối tượng đã có và tất cả những đối tượng mới).
extend
thường là một hàm cấp cao sao chép nguyên mẫu của một lớp con mới mà bạn muốn mở rộng từ lớp cơ sở.
Vì vậy, bạn có thể làm điều gì đó như:
extend( Fighter, Human )
Và phương thức Fighter
khởi tạo / đối tượng sẽ kế thừa nguyên mẫu của Human
, vì vậy nếu bạn định nghĩa các phương thức như live
và die
trên Human
thì Fighter
cũng sẽ kế thừa những phương thức đó.
Đã cập nhật làm rõ:
"hàm cấp cao" nghĩa là .extend không được tích hợp sẵn nhưng thường được cung cấp bởi một thư viện như jQuery hoặc Prototype.
changing the native objects can break other developer's assumptions of these objects,
dẫn đến các lỗi javascript thường có thể mất nhiều giờ để theo dõi. Câu đầu tiên trong câu trả lời này dường như đã xuyên tạc thực hành javascript có giá trị này.
.extend()
được thêm vào bởi nhiều thư viện bên thứ ba để dễ dàng tạo đối tượng từ các đối tượng khác. Xem http://api.jquery.com/jQuery.extend/ hoặc http://www.prototypejs.org/api/object/extend để biết một số ví dụ.
.prototype
đề cập đến "mẫu" (nếu bạn muốn gọi nó như vậy) của một đối tượng, vì vậy bằng cách thêm các phương thức vào nguyên mẫu của đối tượng (bạn thấy điều này rất nhiều trong các thư viện để thêm vào Chuỗi, Ngày, Toán hoặc thậm chí là Hàm) các phương thức đó được thêm vào mọi phiên bản mới của đối tượng đó.
Các extend
phương pháp ví dụ như trong jQuery hoặc PrototypeJS , bản sao tất cả các thuộc tính từ nguồn đến đối tượng đích.
Bây giờ về thuộc prototype
tính, nó là một thành viên của các đối tượng hàm, nó là một phần của lõi ngôn ngữ.
Bất kỳ hàm nào cũng có thể được sử dụng như một phương thức khởi tạo , để tạo các thể hiện đối tượng mới. Tất cả các chức năng đều cóprototype
tính này.
Khi bạn sử dụng new
toán tử với trên một đối tượng hàm, một đối tượng mới sẽ được tạo và nó sẽ kế thừa từ hàm tạo của nóprototype
.
Ví dụ:
function Foo () {
}
Foo.prototype.bar = true;
var foo = new Foo();
foo.bar; // true
foo instanceof Foo; // true
Foo.prototype.isPrototypeOf(foo); // true
Kế thừa Javascript dường như giống như một cuộc tranh luận mở ở khắp mọi nơi. Có thể gọi đây là "Trường hợp kỳ lạ của ngôn ngữ Javascript".
Ý tưởng là có một lớp cơ sở và sau đó bạn mở rộng lớp cơ sở để có được một tính năng giống như kế thừa (không hoàn toàn, nhưng vẫn có).
Toàn bộ ý tưởng là hiểu được ý nghĩa thực sự của nguyên mẫu. Tôi đã không hiểu nó cho đến khi tôi thấy mã của John Resig (gần giống với những gì jQuery.extend
) đã viết một đoạn mã để thực hiện nó và anh ấy tuyên bố rằng base2 và thư viện nguyên mẫu là nguồn cảm hứng.
Đây là mã.
/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* MIT Licensed.
*/
// Inspired by base2 and Prototype
(function(){
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
this.Class = function(){};
// Create a new Class that inherits from this class
Class.extend = function(prop) {
var _super = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// Copy the properties over onto the new prototype
for (var name in prop) {
// Check if we're overwriting an existing function
prototype[name] = typeof prop[name] == "function" &&
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn){
return function() {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) :
prop[name];
}
// The dummy class constructor
function Class() {
// All construction is actually done in the init method
if ( !initializing && this.init )
this.init.apply(this, arguments);
}
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
})();
Có ba phần đang thực hiện công việc. Đầu tiên, bạn lặp qua các thuộc tính và thêm chúng vào phiên bản. Sau đó, bạn tạo một phương thức khởi tạo để sau này được thêm vào đối tượng. Bây giờ, các dòng chính là:
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
Đầu tiên bạn trỏ Class.prototype
đến nguyên mẫu mong muốn. Bây giờ, toàn bộ đối tượng đã thay đổi có nghĩa là bạn cần buộc bố cục trở lại như của chính nó.
Và ví dụ sử dụng:
var Car = Class.Extend({
setColor: function(clr){
color = clr;
}
});
var volvo = Car.Extend({
getColor: function () {
return color;
}
});
Đọc thêm về nó tại đây tại Javascript Inheritance by John Resig 's post.
Một số extend
chức năng trong thư viện của bên thứ ba phức tạp hơn những chức năng khác. Ví dụ: Knockout.js chứa một cái cực kỳ đơn giản không có một số kiểm tra như jQuery's:
function extend(target, source) {
if (source) {
for(var prop in source) {
if(source.hasOwnProperty(prop)) {
target[prop] = source[prop];
}
}
}
return target;
}
.extends()
tạo một lớp là con của lớp khác. Child.prototype.__proto__
thiết lập giá trị của nó để Parent.prototype
.prototype
kế thừa các tính năng từ cái này sang cái khác..__proto__
là getter / setter cho Prototype.
.extend
là "hàm cấp cao" không được tích hợp sẵn nhưng thường được cung cấp bởi một thư viện như jQuery hoặc Prototype.