漫談js-原型

原型

相信js開發者都知道原型,原型鏈,可是不少人暈暈乎乎對此不知甚解。下面分享一下個人我的心得。數組

學習中的困惑

  1. 構造函數,原型,實例對象之間的關係是什麼?
  2. 原型鏈是怎麼繼承的?
  3. 既然構造函數自己是函數,那麼new和直接調用有什麼區別,

解答

構造函數,原型,實例對象之間的關係是什麼?

廢話不說先上圖
圖片描述app

不須要管網上亂七八糟的各類原型鏈指向圖,記住這個就好了。
除了各類指向之外,圖中還包含這些信息:函數

  1. 'prototype'屬性是函數獨有的
  2. __proto__纔是實例的。固然,這個屬性不建議使用。能夠用Object.setPrototypeOfObject.getPrototypeOf

天真的我曾經覺得原型是prototype,那原型鏈就是跟着prototype找...,實在是too young too simple啊。
這裏必定要記住,原型鏈是沿着__proto__鏈找。
圖片描述學習

原型鏈是怎麼繼承的?

其實這個問題也能夠是:當咱們構建對象時,發生了什麼。
舉個簡單例子:this

function father(){
    this.name = "爸爸"
}
father.prototype.family = "愛的家"

var dad = new father();

這裏進行了以下操做:spa

  1. 實例化一個空對象Object.create();
  2. 將father的[[prototype]]屬性委託給father的原型。
  3. 指定上下文。即this爲第一步實例化出來的空對象。
  4. 執行構造函數。

用代碼模擬就是:prototype

function _new(/* 構造函數 */ constructor, /* 構造函數參數 */ param1) {
  // 將 arguments 對象轉爲數組
  var args = [].slice.call(arguments);
  // 取出構造函數
  var constructor = args.shift();
  // 建立一個空對象,繼承構造函數的 prototype 屬性
  var context = Object.create(constructor.prototype);
  // 執行構造函數
  var result = constructor.apply(context, args);
  // 若是返回結果是對象,就直接返回,則返回 context 對象
  return (typeof result === 'object' && result != null) ? result : context;
}

// 實例
var actor = _new(Person, '張三', 28);

記住一點,實例化對象之後,構造函數就沒什麼事了。原型鏈只看構造函數的原型對象和實例化出來的對象。
這裏在說一點,關於,繼承。現實中的繼承就是你的東西給我了,我拿過來了。我可使用,能夠轉讓。可是js中真是這樣嗎?
一個很簡單的問題,若是原型繼承真是把原型中的屬性拷過來那我每次自身找不到屬性還要沿着原型鏈查找幹嗎。
很顯然,js中原型可不是二百五,他所謂的繼承,只是給你使用權,不會給你轉讓權。
上面第二步中:將father的[[prototype]]屬性委託給father的原型。我寫的是委託。這樣描述可能更準確。由於這裏只是至關於給實例化對象一個指針,指向了原型對象。這其實也是下一個問題的答案。指針

既然構造函數自己是函數,那麼new和直接調用有什麼區別

答案揭曉:
只有經過new調用構造函數纔會走第二步,也就是原型的委託操做。
那麼怎麼判斷是否同new調用呢?code

判斷是否通多new調用函數

ES6函數內部可使用new.target屬性。若是當前函數是new命令調用,new.target指向當前函數,不然爲undefined。
ES5對象

if(this instanceof Father){...}

ES6

//在函數外使用new.target是一個錯誤
typeof new.target !== 'undefined'

這裏再多扯一下typeof和instance。反正我之前是每次看了記住了,好久不用又忘了。。。。,看了這麼多原型鏈的內容,再看看這個應該會映象深入吧:

typeof :

用來判斷值類型。如string/number/boolean,但若是判斷引用類型,返回值就只有 object/function。因此沒法進一步判斷是object對象,仍是數組,仍是new Number等等。
注意:

undefined返回undefined。
// 錯誤的寫法
if (v) {
  // ...
}
// ReferenceError: v is not defined

// 正確的寫法
if (typeof v === "undefined") {
  // ...
}

instanceof :

根據原型鏈判斷引用類型。A instanceof B,判斷原則是沿着 A 的__proto__這條線來找,同時沿着 B 的 prototype 這條線來找,若是兩條線能找到同一個引用,即同一個對象,那麼就返回 true。若是找到終點還未重合,則返回 false。

相關文章
相關標籤/搜索