# Prototypal inheritance

## \[\[Prototype]]

物件有一個特殊隱藏屬性 \[\[Prototype]]，他指向 null 或者其他物件。從物件讀取物件時，這個屬性會自動消失，取而代之的是指向的原型物件。

![](/files/-LhnWvTalQM1BgCMWabM)

```javascript
// 設定 [[Prototype]] 的方法
let animal = {
  eats: true
};
let rabbit = {
  jumps: true
};

rabbit.__proto__ = animal;

// __proto__ 是 [[Prototype]] 的訪問函式

// 在 rabbit 找不到的屬性會在 animal 找
let animal = {
  eats: true
};
let rabbit = {
  jumps: true
};

rabbit.__proto__ = animal; // (*)

// we can find both properties in rabbit now:
alert( rabbit.eats ); // true (**)
alert( rabbit.jumps ); // true
```

![](/files/-LhnXpERZnCf4lSU7m9v)

```javascript
// 在 rabbit 找不到的方法會在 animal 找
let animal = {
  eats: true,
  walk() {
    alert("Animal walk");
  }
};

let rabbit = {
  jumps: true,
  __proto__: animal
};

// walk is taken from the prototype
rabbit.walk(); // Animal walk
```

![](/files/-LhnYKELozG15eBoqehK)

```javascript
let animal = {
  eats: true,
  walk() {
    alert("Animal walk");
  }
};

let rabbit = {
  jumps: true,
  __proto__: animal
};

let longEar = {
  earLength: 10,
  __proto__: rabbit
};

// walk is taken from the prototype chain
longEar.walk(); // Animal walk
alert(longEar.jumps); // true (from rabbit)

// 指向不能形成循環會出錯誤
// __proto__ 的值只能是 null 或物件，其他值會被忽略
// 一個物件只能繼承一個物件
```

![](/files/-LhnYhO9my9k8MOqs04N)

## Writing doesn’t use prototype

原型繼承對於資料類型的屬性只能使用 get，無法使用  set，也就是無法更改只能讀取；訪問類型的屬性如果 get、set都有則可以讀取、更改。

```javascript
// data property 不能更改
let animal = {
  eats: true,
  walk() {
    /* this method won't be used by rabbit */
  }
};

let rabbit = {
  __proto__: animal
};

rabbit.walk = function() {
  alert("Rabbit! Bounce-bounce!");
};

rabbit.walk(); // Rabbit! Bounce-bounce!
```

![](/files/-LhnZjJ6TW532d1f7N0S)

```javascript
// accessors property 有設置 get、set 可以更改
let user = {
  name: "John",
  surname: "Smith",

  set fullName(value) {
    [this.name, this.surname] = value.split(" ");
  },

  get fullName() {
    return `${this.name} ${this.surname}`;
  }
};

let admin = {
  __proto__: user,
  isAdmin: true
};

alert(admin.fullName); // John Smith (*)

// setter triggers!
admin.fullName = "Alice Cooper"; // (**)
```

## The value of “this”

```javascript
// this 指向使用方法的物件
// animal has methods
let animal = {
  walk() {
    if (!this.isSleeping) {
      alert(`I walk`);
    }
  },
  sleep() {
    this.isSleeping = true;
  }
};

let rabbit = {
  name: "White Rabbit",
  __proto__: animal
};

// modifies rabbit.isSleeping
rabbit.sleep();

alert(rabbit.isSleeping); // true
alert(animal.isSleeping); // undefined (no such property in the prototype)
```

![](/files/-Lhnau4jv9Bch98nEptQ)

## for…in loop

```javascript
// for..in 會返回包含原型的屬性
let animal = {
  eats: true
};

let rabbit = {
  jumps: true,
  __proto__: animal
};

// Object.keys only return own keys
alert(Object.keys(rabbit)); // jumps

// for..in loops over both own and inherited keys
for(let prop in rabbit) alert(prop); // jumps, then eats

// 如果不想返回原型的屬性可以用 hasOwnProperty()
let animal = {
  eats: true
};

let rabbit = {
  jumps: true,
  __proto__: animal
};

for(let prop in rabbit) {
  let isOwn = rabbit.hasOwnProperty(prop);

  if (isOwn) {
    alert(`Our: ${prop}`); // Our: jumps
  } else {
    alert(`Inherited: ${prop}`); // Inherited: eats
  }
}
```

![](/files/-Lhnbf2E9SxMA_oRra3e)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mistborn.gitbook.io/til-coding/javascript/prototypal-inheritance.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
