JavaScript Prototype 繼承、原型鏈 Prototype chain

JavaScript Prototype 繼承、原型鏈 Prototype chain

August 25, 2018

·

5 min read

因緣際會之下,最近剛經歷了招募前端,為了準備面試題目,所以整理了一些關於 JavaScript 的 觀念,其中比較抽象的題目應該是 ProtoType、Event loop、Bubbles Capture,這邊就先來介紹一下其中最抽象也比較難理解的 JavaScript ProtoType。

JavaScript ProtoType 介紹

JavaScript 沒有類的特性(class-based),跟 Java 不一樣,雖然說 ES6 有 class 但它只是語法糖,每個 JavaScript 都具備有 prototype,只是分為公開、私有差異,而 JavaScript 就用 prototype 來處理繼承(prototype-based),特性是延展性高。

// 使用解構復值作為參數  並且預設沒傳值預設給予字串
function Family({ m = "no person", w = "no person", c = "no child" } = {}) {
  this.father = m;
  this.mother = w;
  this.chidren = c;
}

var data = {
  m: "John Paul",
  w: "Mary Alice",
  c: "Chris Paul",
};

// 繼承 Family
var paul = new Family(data);
// 等同於
// var paul[[Prototype]] = Family.prototype;
// Family.call(paul);
// paul 的 __proto__ 等於 Family();

console.log(paul);
// chidren: "Chris Paul"
// father: "John Paul"
// mother: "Mary Alice"

example codepen

console.log(paul) 截圖

JavaScript proto
family proto.proto

接下來擴充一下 Family,增加一個 function。

// 增加一個 hi function
Family.prototype.hi = function () {
  console.log(
    `Family's child is ${this.chidren}. Family's father is ${this.father}`
  );
};

// this 指向調用時的物件 paul
paul.hi();
// I am Chris Paul. My father is John Paul

example codepen

JavaScript ProtoType 用來建立 function 也較不耗費記憶體,當我今天有多個的不同物件要產生,就不需要實際複製產生,而是轉向繼承核心的 function 使用 prototype,這特色在 es6 class 撰寫時會滿明顯感受。

JavaScript ProtoType 繼承鍊

每個物件都有一個連著其他原型(prototype)的私有屬性(private property)物件。原型物件也有著自己的原型,於是原型物件就這樣鏈結,直到撞見 null 為止。看範例可能會比較好理解,

另外會發現到物件第一層會是 __proto__ (隱式原型),主要是瀏覽器會透過隱式原型指向該物件的 prototype。

ps. __proto__稱為隱式原型) 與 prototype 顯式原型。

JavaScript protochain
family protochain

簡單的範例

var Person = function () {
  this.name = `chu`;
};

var Age = function () {
  this.age = 18;
};

var Gender = function () {
  this.gender = "male";
};

Age.prototype = new Person();

Gender.prototype = new Age();

var ian = new Gender();
console.log(ian.name, ian.age, ian.gender); // chu 18 male
// 會先查找 ian 的 name ,找不到找該物件的原型prototype,
// 在找不到會在往上層去找 prototype.name 就會發現找到了停止向上查找
// 直到找不到 prototype ,__proto__為null時停止
// 整個流程稱之為 prototype chain

example codepen

JavaScript protochain
family protochain

突然提到 prototype,主要是在 React 開發時,時常用到 ES6 class,才知道 class 背後處理了非常關於 prototype 繼承的細節。才知道 prototype 的概念形影不離。

例如一個簡單的 class 如下

class Person {
  constructor(name) {
    this.name = name;
  }
  hello() {
    console.log(`hello,i am ${this.name}`);
  }
}
class Age extends Person {
  // constructor會在建立時倍呼叫
  // 接受傳遞參數
  constructor(name, age) {
    // 繼承父層 prototype.name
    super(name);
    this.age = age;
  }
  intro() {
    console.log(`i am ${this.name}, and ${this.age} years old,`);
  }
}

const ian = new Age(`chu`, 18);
ian.intro(); // i am chu, and 18 years old,
ian.hello(); // hello,i am chu

example codepen

如果你有用過 react 的 class xxx extends React.component,就會發現到其中 super(props),就在講繼承 React.component 的 props。es6 class 就先不在這邊講述了,

以上就是 prototype 的簡單介紹,有錯誤或是問題歡迎留言。