原型继承对象的多个实例

发布于 2024-12-11 11:10:57 字数 2661 浏览 0 评论 0原文

我正在尝试掌握使用原型继承的方法。这是我下面的代码。它基于 Stoyan Stefanov 的《面向对象的 Javascript》一书,仅做了一些修改。

基本上我有一个 Athlete 对象,它扩展了 Person 对象。我创建了 3 个对象。鲍勃是一个,而比利·吉恩和史蒂夫是运动员。我按照特定的顺序添加了鲍勃、比利·吉恩和史蒂夫。我调用了 say()run() 函数以及 getSpeed()jump(),对于 < code>Athlete 对象,所有 3 个对象均按此特定顺序排列:Bob、Billy Jean 和 Steve。

这是下面的代码。

<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 的函数,但 Steve 的属性会弹出两次,这意味着 Steve 替换了 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

我只是想知道是否有办法将比利·吉恩和史蒂夫分开,以便我两次获得他们的详细信息而不是史蒂夫的详细信息?

如果不可能,那么我可以使用什么替代方案来解决这个问题?任何解决方案或帮助都会有很大的帮助。

I'm trying to get the grips of using prototypal inheritance. Here is the code I have below. It is based on the book "Object -Oriented Javascript" by Stoyan Stefanov, with just a few modifications.

Basically I have an Athlete object that extends a Person object. I have created 3 objects. Bob is a Person, while Billy Jean and Steve are Athletes. I added Bob, Billy Jean and Steve in that particular order. I invoked say() and run() functions and getSpeed() and jump(), for the Athlete objects, in all 3 objects in this particular order: Bob, Billy Jean and Steve.

Here is the code below.

<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>

However, when I run the code, although I invoke the functions for Billy Jean first, Steve's properties pop up twice, meaning Steve replaced Billy Jean. Output shown below.

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

I was just wondering if there is a way to separate Billy Jean and Steve So that I get both their details instead of Steve's details twice?

If it's impossible then what alternative can I use instead to solve this problem? Any solution or help would be a great help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

2024-12-18 11:10:57

此特定行在 Athlete.initialize 的示例中存在问题:

//uber is the parent
this.uber.initialise(name);

通过此调用,您可以在 uber 表示的对象上调用 initialize ,该对象是共享的在你的运动员中。将此更改为:

this.uber.initialize.call(this, name);

从您的实际对象(this)上调用初始化,传递附加参数。

This particular line is problematic in your example in Athlete.initialize:

//uber is the parent
this.uber.initialise(name);

With this call, you call initialize on object represented by uber, which is shared among your athlets. Change this to:

this.uber.initialize.call(this, name);

to call initialize from uber on your actual object (this) passing additional paremeters.

葬花如无物 2024-12-18 11:10:57

这是你的问题。 “this.uber”引用了 steve 和 billyJean 之间共享的对象。对象是通过引用传递的,所以这就是发生这种情况的原因。尝试替换

this.uber.initialise(name); 

this.uber.initialise.call(this, name); 

(如果您不知道,“调用”和“应用”使“方法”在不同的范围内运行)。我对你的经历没有任何真实的背景,所以希望接下来的闲聊不会侮辱......但是,有一些想法。我很少看到 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();

这也同样有效。请注意,我在这里仍然使用“调用” - 这是因为原始数据是通过引用传递的。你可以撤消这个操作.. 让它通过克隆.. 但实际上,90% 的时间这都是内存和循环的浪费。

所以,这就是我最好的“纯粹”方法!我个人不喜欢这种方式,因为我将“steve”和“billyJean”视为“新”运动员 - 而不是运动员对象的克隆 - 所以我更倾向于使用一种模式,让我可以执行“steve =”新运动员('史蒂夫');'

我的两分钱,希望有帮助。

Here's your issue. "this.uber" is referencing an object that is shared between steve and billyJean. Objects are passed around by reference, so that's why this is happening. Try replacing

this.uber.initialise(name); 

with

this.uber.initialise.call(this, name); 

(In case you aren't aware, 'call' and 'apply' make 'methods' run in different scopes). I don't have any real background on your experience, so hopefully this next ramble isn't insulting.. but, a few thoughts. I've rarely seen javascript done like this. Most of the time it has been something more along the lines of...

var bob = new Person(); 
bob.initialise('Bob');
bob.say();
bob.run();

Why the 'clone'? Did you want a purist approach? If so, the 'clone' isn't any better - you're still calling 'new' and doing a little magic. A purist approach would be more of.. (pardon the jQuery.. being lazy)

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();

This works just as well. Note that I'm still using 'call' here - it's because the original is passed by reference. You could undo that.. make it pass a clone.. but really, it's a waste of memory and cycles 90% of the time.

So, there's my best 'purist' approach! I personally don't like this way, as I see 'steve' and 'billyJean' as 'new' Athletes - not clones of an Athletes object - so I'd be more inclined to use a pattern that lets me do 'steve = new Athlete('Steve');'

My two cents, hope it helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文