下面的代码是我见过的最好的 JavaScript 继承代码之一。
Object.create(proto [, propertiesObject ]) 在 MDN here上进行了讨论。
下面,Jon 定义了一个名为 ExtendBase 的基本空对象,然后添加了一个名为 extend 的函数属性,该属性不可枚举,它将单个新对象作为其参数。
该对象应包含可枚举的属性,例如将添加到基础对象的方法和数据。
他从传递的对象中获取所有可枚举的属性,然后创建一个必要的描述符数组,以使用这些属性的名称传递给 Object.create。然后,他使用父对象作为原型,并将结果描述符作为新属性,直接在 Object.create() 调用中添加到子对象。
如您所见,您可以使用带有属性(包括方法)的对象参数来扩展父对象,而不会丢失传递的对象的属性,结果是子对象,以父对象为原型,并直接添加传递对象的可枚举对象给孩子。
然而,这维护了一个干净的原型链,同时打算使用其他对象扩展父对象,这些对象是合理创建的,以一种有意义的方式将父对象扩展到新子对象:
现场示例(在Chrome 中按 F12 进行控制台输出,或在 FireFox 中使用 FireBug 等)
JavaScript:
// Original Author: FireFly - Jonas Höglund - ##javascript channel
// on irc.freenode.net - see THANKS File. Updated to private data
// members and passable initial parameters by Scott Sanbar
///////////////
// Library code
///////////////
var ExtendBase = {};
Object.defineProperty(ExtendBase, 'extend', {
enumerable:false, value:function (obj) {
'use strict';
var descs = {};
Object.getOwnPropertyNames(obj).forEach(function (key) {
descs[key] = Object.getOwnPropertyDescriptor(obj, key)
});
return Object.create(this, descs);
}
});
///////////////
// Sample Usage
///////////////
function PersonObj(nam) {
return {
name:new function () {
var name = nam;
this.set = function (value) {
name = value;
};
this.get = function () {
return name;
}
},
// A person can tell you its name.
talk:function () {
return "Hello, I'm " + this.name.get();
}
}
}
;
function WorkingPersonObj(occ) {
return {
occupation:new function () {
var occupation = occ;
this.set = function (value) {
occupation = value;
};
this.get = function () {
return occupation;
}
},
// A working person also tells you their occupation when they talk.
talk:function () {
return Person.talk.call(this) + " and I am a " + this.occupation.get();
}
}
}
;
var hush = {
hush:function () {
return "I am supposed to be quiet";
}
};
var Person = ExtendBase.extend(new PersonObj('Harry'));
var WorkingPerson = Person.extend(new WorkingPersonObj('wizard'));
var wp1 = WorkingPerson.extend(hush);
console.log(wp1.talk()); // "Hello, I'm Harry and I am a wizard"
console.log(wp1.hush()); // "I am supposed to be quiet"
wp1.name.set("Elijah");
wp1.occupation.set("prophet");
console.log(wp1.talk()); // "Hello, I'm Elijah and I am a prophet"
console.log(wp1.name.get());
console.log(wp1.occupation.get());