我正试图抓住使用原型继承的把握。这是我下面的代码。它基于Stoyan Stefanov撰写的“面向对象的Javascript”一书,只做了一些修改。
基本上我有一个扩展Athlete
对象的Person
对象。我创建了3个对象。 Bob是Person
,而Billy Jean和Steve是Athletes
。我按照特定顺序添加了Bob,Billy Jean和Steve。我为这些特定顺序的所有3个对象中的say()
个对象调用了run()
和getSpeed()
函数以及jump()
和Athlete
:Bob,Billy Jean和史蒂夫。
以下是代码。
<script type="text/javascript">
function clone(o) {
var n;
function F(){};
F.prototype = o;
n = new F();
return n;
}
/* Uber is equivalent to the extends method */
function uber(parent, child) {
var n = clone(parent);
n.uber = parent;
for (var i in child) {
n[i] = child[i];
}
return n;
}
var Person = {
initialise: function(name)
{
this.name = name;
},
say: function()
{
console.log('My name is ' + this.name + '. I am a person');
},
run: function(){
console.log('I have run 5km');
},
jump: function() {
console.log('I have jumped for joy!');
}
};
var Athlete = {
initialise: function(name,speed) {
this.speed = speed;
//uber is the parent
this.uber.initialise(name);
},
say: function() { console.log('My name is ' + this.name + '. I am an athlete');},
run: function() { console.log('I have run 20km'); this.jump()},
getSpeed: function() {console.log('My Speed is: ' + this.speed + 'km Hour');}
}
var Athlete = uber(Person, Athlete);
console.log("Hello, Starting Test...");
var bob = clone(Person);
bob.initialise('Bob');
bob.say();
bob.run();
console.log("Adding Billy Jean...");
var billyJean = clone(Athlete);
billyJean.initialise('Billy Jean', 15);
console.log("Adding Steve...");
var steve = clone(Athlete);
steve.initialise('Steve', 25);
console.log("Asking Billy Jean...");
billyJean.say();
billyJean.run();
billyJean.getSpeed();
console.log("Asking Steve...");
steve.say();
steve.run();
steve.getSpeed();
</script>
但是,当我运行代码时,虽然我首先调用Billy Jean的功能,但史蒂夫的属性会弹出两次,这意味着史蒂夫取代了Billy Jean。输出如下所示。
Hello, Starting Test...
My name is Bob. I am a person
I have run 5km
Adding Billy Jean...
Adding Steve...
Asking Billy Jean...
My name is Steve. I am an athlete
I have run 20km
I have jumped for joy!
My Speed is: 15km Hour
Asking Steve Tran...
My name is Steve. I am an athlete
I have run 20km
I have jumped for joy!
My Speed is: 25km Hour
我只是想知道是否有办法将Billy Jean和Steve So分开,我得到他们的细节而不是史蒂夫的细节两次?
如果不可能,那么我可以使用哪种替代方案来解决这个问题?任何解决方案或帮助都将是一个很大的帮助。
答案 0 :(得分:1)
这个特定的行在Athlete.initialize中的示例中存在问题:
//uber is the parent
this.uber.initialise(name);
通过此次通话,您可以在initialize
代表的对象上拨打uber
,该对象在您的运动员之间共享。将其更改为:
this.uber.initialize.call(this, name);
从 致电initialize
您的实际对象(此)传递额外的参数。
答案 1 :(得分:0)
这是你的问题。 “this.uber”引用了一个在steve和billyJean之间共享的对象。对象通过引用传递,这就是为什么会发生这种情况。尝试替换
this.uber.initialise(name);
带
this.uber.initialise.call(this, name);
(如果您不知道,'call'和'apply'make'方法'在不同的范围内运行)。我对你的经历没有任何真实的背景,所以希望下一次漫步不是侮辱......但是,一些想法。我很少见到像这样的javascript。大多数时候,它更像是......
var bob = new Person();
bob.initialise('Bob');
bob.say();
bob.run();
为什么'克隆'?你想要纯粹的方法吗?如果是这样,那么'克隆'就没有任何好处 - 你仍然在称'新'并且做一点魔术。一种纯粹主义的方法更多......(原谅jQuery ......懒惰)
Object.prototype.clone = function () {
return $.extend(true, {}, this);
};
Object.prototype.improve = function (extras) {
var spawn = $.extend(true, {}, this, extras);
spawn.uber = this;
return spawn;
};
var Person = {
initialise: function(name) {
this.name = name;
},
say: function() {
console.log('My name is ' + this.name + '. I am a person');
},
run: function(){
console.log('I have run 5km');
},
jump: function() {
console.log('I have jumped for joy!');
}
};
var Athlete = Person.improve({
initialise: function(name,speed) {
this.speed = speed;
//uber is the parent
this.uber.initialise.call(this, name);
},
say: function() { console.log('My name is ' + this.name + '. I am an athlete');},
run: function() { console.log('I have run 20km'); this.jump()},
getSpeed: function() {console.log('My Speed is: ' + this.speed + 'km Hour');}
});
var bob = Person.clone();
bob.initialise('Bob');
bob.say();
bob.run();
console.log("Adding Billy Jean...");
var billyJean = Athlete.clone();
billyJean.initialise('Billy Jean', 15);
console.log("Adding Steve...");
var steve = Athlete.clone();
steve.initialise('Steve', 25);
console.log("Asking Billy Jean...");
billyJean.say();
billyJean.run();
billyJean.getSpeed();
console.log("Asking Steve...");
steve.say();
steve.run();
steve.getSpeed();
这同样有效。请注意,我仍然在这里使用'call' - 因为原件是通过引用传递的。你可以撤消它...让它通过一个克隆..但实际上,这是浪费内存和90%的时间循环。
所以,这是我最好的'纯粹'方法!我个人不喜欢这种方式,因为我认为'steve'和'billyJean'是'新'运动员 - 而不是运动员对象的克隆 - 所以我更倾向于使用一种模式让我做'史蒂夫=新运动员('史蒂夫');'
我的两分钱,希望它有所帮助。