2012-01-04 273 views
6

我试图将原型继承应用于Javascript中的函数。这一切都很简单,甚至在Wikipedia's javascript lemma中有描述。它的工作原理,如果我的属性是简单的JavaScript类型:javascript原型继承和对象属性

function Person() { 
    this.age = 0; 
    this.location = { 
     x: 0, 
     y: 0, 
     absolute: false 
    }; 
}; 

function Employee() {}; 

Employee.prototype = new Person(); 
Employee.prototype.celebrate = function() { 
    this.age++; 
} 

var pete = new Employee(); 
pete.age = 5; 
pete.celebrate(); 
var bob = new Employee(); 
bob.celebrate(); 
console.log("bob is " + bob.age + " pete is " + pete.age); 

随着Employee.prototype = new Person();,所有的人的属性和(原型)的方法是由雇员,这是基本的继承继承。

这按预期工作:bob is 1 pete is 6

现在,我开始与皮特的位置摆弄(后庆祝)

pete.celebrate(); 
pete.location.absolute=true; 

显示bob.location.absolute显示:true,这是禁忌直观(我没有碰bob的位置,所以我期望它的初始值在Person中声明),并且破坏了我的解决方案。

在我最初的理解中,这应该是错误的。我意识到我可能应该从最初的人克隆位置对象,但我不确定在哪里或如何做到这一点。 如果还有更好的继承技术?

回答

3

当你实例化一个新的Employee时,Person的所有属性都被复制。由于这是一个浅拷贝,皮特和鲍勃共享相同的位置对象。对于你的问题,似乎没有一个很好的解决方案。您可以使用一个框架或做这样一个黑客:

function Employee() { Person.apply(this); }; 

这就要求在此对象的上下文中的人物构造。

的MDC有更多关于这方面的信息:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply

3

继承时,不要运行Person构造函数,Employee不 甚至应该有一个.location,因为它不是在Person.prototype

function createObject(fn){ 
    function f(){} 
    f.prototype = fn.prototype; 
    return new f; 
} 

然后:

Employee.prototype = createObject(Person); 

这将正确继承没有副作用(运行构造函数)。

你只运行在孩子的构造函数的父类的构造:

function Employee() { 
Person.apply(this, arguments); 
} 
+0

使用createObject(Person)而不是新Person()的好处是什么?它只增加了一层间接原型。 – Kosta 2012-01-04 10:10:21

+0

@Kosta可以避免继承时运行构造函数的副作用。构造函数通常在其中有初始化代码,当你没有实例化任何东西时,你不想运行。 '新员工'仍然是'instanceof Person',因为'Person.prototype'和'f.prototype'指向同一个对象。 – Esailija 2012-01-04 10:13:12

+0

但是你仍然在createObject()中运行构造函数(一次)。此外,您正在运行Employee()中的构造函数(在每个实例化上)。你能举一个例子,其中createObject()是有用的吗? – Kosta 2012-01-04 10:29:17

0

我遇到了类似的问题。我最终为内部对象使用了一个单独的构造函数。

function engine(cc, fuel) { 
     this.cc = cc; 
     this.fuel = fuel 
} 

function car(type, model, cc, fuel) { 
     this.type = type; 
     this.model = model; 
     this.engine = new engine(cc, fuel); 
} 


var mycar = new car("sedan", "toyota corolla", 1500, "gas"); 
console.log(mycar.type); 
//sedan 
console.log(mycar.engine.cc); 
//1500 

如果我在'engine'或'car'构造函数的原型上有任何方法,它们仍然可用。但是,我不是从OOP意义上的“引擎”类中推导出“汽车”类。我不需要。 “引擎”被用作“汽车”的组件。同时,为了继承,我更喜欢使用ECMAScript 5中包含的新方法,这意味着使用Object.create,Object.defineProperties等,即使在IE9中也支持它们。在此之前,我使用了Kosta建议的相同'apply()'方法。