2017-09-02 73 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答案 - 這是比我還要好。