我发现这是在JavaScript中执行继承的最建议的方法。
function extend(Child, Parent) {
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
}
如果我已经有孩子的原型中有方法,不是我们会覆盖,我们是否应该保留它们。
function extend(Child, Parent) {
var c = child.prototype;
var oldProto = new C();
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
for(var i in oldProto ){
Child.prototype[i] = oldProto[i]
}
}
我不确定这对您有好处,但要记住很重要:原型与类不同。您正在做的是试图使JS表现得像传统的OO语言,该语言正试图教一只海豚跳舞芭蕾舞,或迫使老虎成为素食主义者:令人钦佩,但注定要流泪。
我真的看不到为什么您要使用extend
函数来执行您要做的任何事情。为什么不简单地使用它:
function Parent()
{};
function Child()
{};
//augment parent proto
Parent.prototype.parentMethod1 = function()
{};
//set Child's proto to Parent
Child.prototype = new Parent();
Child.prototype.constructor = Child;
//Then augment the Child's prototype
Child.prototype.childMethod1 = function()
{};
var foo = new Child();
foo.parentMethod1();//works
foo.childMethod1();//works, too
imo,这完全解决了问题。当然,这有点详细,但是OOP总是如此。
您要实现的模式称为多个继承。由于您遇到的问题,它被称为钻石问题,因此不建议用于使用。只需使用Mixin模式即可。
下面的代码是我在JavaScript中执行继承的最好的代码。
object.create(proto [,propertiesObject])在此处讨论
下面,乔恩(Jon
该对象应包含可以添加到基本对象的方法和数据等枚举属性。
他从传递的对象中获取所有枚举的属性,然后创建一个必要的描述符数组以传递到对象中。使用这些属性的名称创建。然后,他将父对象用作原型和结果描述符,作为要直接在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());