2017-09-02 92 views
0

我对通过原型和'this'关键字在JavaScript中实现继承存在一些困惑。关于'this'的混淆和JavaScript中的原型设计

let person = { 
 
    stomach: [], 
 

 
    eat(food) { 
 
    this.stomach.push(food); 
 
    } 
 
}; 
 

 
let tony = { 
 
    __proto__: person 
 
}; 
 

 
let peter = { 
 
    __proto__: person 
 
}; 
 

 
tony.eat("shawarma"); 
 
alert(tony.stomach); // shawarma 
 

 

 
alert(peter.stomach); // shawarma

在上面的例子,为什么最后一行给出了答案“沙威玛”即使没有被推倒?

+0

因为JavaScript正在寻找'peter .__ proto __。stomach'。请参阅https://basarat.gitbooks.io/typescript/docs/classes-emit.html –

+0

https://stackoverflow.com/questions/16394709/why-this-behaviour-proto-vs-prototype –

+0

'__proto__'这两个点到同一个对象'人' –

回答

1

因为无论tonypeter分享该阵列,这是在person。只有一个数组,你只是改变它的状态。

您创建tonypeter后,在内存中有这样的(忽略细节):

 
           +−−−−−−−−−−+     
person−−−−−−−−−−−−−−−−−−−+−+−−>| (Object) |     
         // +−−−−−−−−−−+  +−−−−−−−−−−−+ 
         | | | stomach |−−−−−>| (Array) | 
         | | +−−−−−−−−−−+  +−−−−−−−−−−−+ 
         | |      | length: 0 | 
         | |      +−−−−−−−−−−−+ 
     +−−−−−−−−−−−+ | | 
tony−−−−>| (Object) | | | 
     +−−−−−−−−−−−+ | | 
     | __proto__ |−−+ | 
     +−−−−−−−−−−−+ | 
          | 
     +−−−−−−−−−−−+ | 
peter−−−>| (Object) | | 
     +−−−−−−−−−−−+ | 
     | __proto__ |−−−−+ 
     +−−−−−−−−−−−+ 

无论您通过tony.__proto__.stomachpeter.__proto__.stomach访问阵列(通过原型链),你所访问只是一个阵列。当您通过eat上推"shawarma",一个阵列的状态,体改,可见无论你走的路才能到它:

 
           +−−−−−−−−−−+     
person−−−−−−−−−−−−−−−−−−−+−+−−>| (Object) |     
         // +−−−−−−−−−−+  +−−−−−−−−−−−−−−−+ 
         | | | stomach |−−−−−>| (Array) | 
         | | +−−−−−−−−−−+  +−−−−−−−−−−−−−−−+ 
         | |      | length: 1  | 
         | |      | 0: "shawarma" | 
     +−−−−−−−−−−−+ | |      +−−−−−−−−−−−−−−−+ 
tony−−−−>| (Object) | | | 
     +−−−−−−−−−−−+ | | 
     | __proto__ |−−+ | 
     +−−−−−−−−−−−+ | 
          | 
     +−−−−−−−−−−−+ | 
peter−−−>| (Object) | | 
     +−−−−−−−−−−−+ | 
     | __proto__ |−−−−+ 
     +−−−−−−−−−−−+ 

你会被给予tonypeter他们自己解决这个stomach S,大概除去stomachperson(尽管你可以离开它,如果你想直接使用person以及使用它作为原型):

let person = { 
 
    stomach: [], // You may or may not want to remove this, depending 
 
    eat(food) { 
 
    this.stomach.push(food); 
 
    } 
 
}; 
 

 
let tony = { 
 
    __proto__: person, 
 
    stomach: [] 
 
}; 
 

 
let peter = { 
 
    __proto__: person, 
 
    stomach: [] 
 
}; 
 

 
tony.eat("shawarma"); 
 
console.log(tony.stomach); // shawarma 
 

 
console.log(peter.stomach); // empty

+0

我需要变得快很多_在拥挤的标签中回答:( –

+0

@suraj:在这种情况下,我们都应该去寻找重复而不是回答;我意识到我是愚蠢的,并没有采取长期以来找到一个dupetarget。 –

0

tony.hasOwnProperty("stomach")将返回false(因为它是不是有什么其他的面向对象语言调用财产),现雏形(如类属性静态成员)的一部分。每个使用它的对象都有一个原型。

因此,任何具有person作为其__proto__prototype的对象将共享相同的stomach

可以,用ES6,而不是使用:

class Person{ 
    constructor(){ 
    this.stomach = []; 
    } 

    eat(food){ 
    this.stomach.push(food); 
    } 
} 

const tony = new Person(); 
const peter = new Person(); 

class RandomPelo extends Person{ 
    constructor(){ 
    super(); 
    this.randomness = true; 
    } 

    eat(food){ 
    super.eat(food); 
    this.weird_shared_stomach.push(food); 
    } 
} 

const pelo = new RandomPelo(); 

NB:
class关键字是围绕构造函数的概念只是语法糖,因此,你也可以修改它的原型添加“静态” 的属性:

RandomPelo.prototype.weid_shared_stomach = [];

0

因为“胃”是原型的特性,对于托尼和彼得对象完全一样。您需要为每个新创建的对象重新初始化构造函数中的“胃”属性。

而且尽量避免https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto

class Person { 
    constructor() { 
     // created separately for every new object 
     this.stomach = []; 
    } 

    eat(food) { 
     this.stomach.push(food); 
    } 
} 

var tony = new Person(); 
var peter = new Person(); 
0

这是引用,因为这两个tonypeter共享相同person原型包含stomach财产。

当您触发tony.eat('shawarma')eat方法正在启动与this指向person对象。所以这个人的胃正在改变。

如果你给petertony自己的肚子,一切都会奏效;)。

let person = { 
    eat(food) { 
    this.stomach.push(food); 
    } 
}; 

let tony = { 
    stomach: [], 
    __proto__: person 
}; 

let peter = { 
    stomach: [], 
    __proto__: person 
}; 

编辑: 刚才看到@wookieb答案 - 这是比我还要好。