简体   繁体   English

原型继承对象的多个实例

[英]Prototypal Inheritance Multiple Instances of Objects

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. 它基于Stoyan Stefanov撰写的“面向对象的Java脚本”一书,仅作了一些修改。

Basically I have an Athlete object that extends a Person object. 基本上,我有一个扩展了Person对象的Athlete对象。 I have created 3 objects. 我创建了3个对象。 Bob is a Person , while Billy Jean and Steve are Athletes . 鲍勃是Person ,比利•简和史蒂夫是Athletes I added Bob, Billy Jean and Steve in that particular order. 我按特定顺序添加了Bob,Billy Jean和Steve。 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. 我为Athlete对象调用了say()run()函数以及getSpeed()jump() ,并按以下特定顺序在所有三个对象中:Bob,Billy Jean和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. 但是,在运行代码时,尽管我先为Billy Jean调用了函数,但Steve的属性弹出了两次,这意味着Steve替换了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? 我只是想知道是否有一种方法可以将Billy Jean和Steve分开,以便我两次获得他们的详细信息,而不是Steve的详细信息两次?

If it's impossible then what alternative can I use instead to solve this problem? 如果不可能,那么我可以使用什么替代方案来解决此问题? Any solution or help would be a great help. 任何解决方案或帮助都会有很大帮助。

This particular line is problematic in your example in Athlete.initialize: 在您的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. 通过此调用,您将对uber表示的对象调用initialize ,该对象在uber之间共享。 Change this to: 更改为:

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

to call initialize from uber on your actual object (this) passing additional paremeters. 通过额外的参数您的实际对象(this) 的uber调用initialize

Here's your issue. 这是你的问题。 "this.uber" is referencing an object that is shared between steve and billyJean. “ this.uber”引用的是在史蒂夫和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. 我很少见过像这样的javascript。 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) 一个纯粹的方法会更多..(对不起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();

This works just as well. 这也一样。 Note that I'm still using 'call' here - it's because the original is passed by reference. 请注意,我在这里仍在使用'call'-这是因为原始文件是通过引用传递的。 You could undo that.. make it pass a clone.. but really, it's a waste of memory and cycles 90% of the time. 您可以撤消该操作..使其通过克隆..但实际上,这浪费了内存,并且90%的时间都在循环。

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');' 我个人不喜欢这种方式,因为我将“ steve”和“ billyJean”视为“新”运动员-而不是运动员对象的克隆-因此,我更倾向于使用一种让我做“ steve =新运动员('史蒂夫');'

My two cents, hope it helps. 我的两分钱,希望对您有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM