天天看點

徹底深刻了解js原型鍊之prototype,__proto__以及constructor(二)

前言

如果你能夠啃下教程一并且吃透原型鍊的幾個概念的話說明你在前端飛仙的路上又進了一小步···學習最怕的不是慢而是站!這篇教程主要目的對原型鍊概念進一步加深了解

鞏固下教程一的知識

來看下面的例子:

var text=new String("我是文字");
function Persion(name,job){
    this.name=name;
    this.job=job;
}
Persion.myName="lxm";
Persion.prototype.sayName=function(){
    alert(this.name);
}
var perison1=new Persion("lxm","20")           

思考:判斷下清單達式傳回的值:

(兩分鐘之内對八道的算及格,剩下的同學回頭接着了解教程一,傳送門在此 [

http://0313.name/2017/01/13/prototype-proto-constructor.html]
perison1.__proto__===Persion.prototype;
perison1.name===Persion.name;
perison1.prototype.__proto__===Object.prototype;
Persion.prototype.__proto__===Object.prototype;
Persion.__proto__===Function.prototype;
Persion.constructor===perison1;
Function.__proto__===Object.prototype;
Function.prototype.__proto__===Object.prototype;
typeof Persion.prototype;
typeof Function.prototype;           

原型鍊圖

這個圖絕對是網絡上獨一無二獨一份,此乃小米飛升教程獨家秘籍!因為部落客在學習過程中發現對文字的了解和記憶遠遠不如一個圖來的更深更直覺,更加透徹,為了您更好的學習原型鍊,部落客特意花了一上午的時間用mermaid繪制了這個原型鍊的關系圖,而且通過這個圖我們能夠發現很多有意思的事情

為了關系圖更加直覺和清晰,隐去了一些引用線路,其中:

  • 圓形代表對象的名字
  • 方形代表屬性名
  • 實線代表對象的分界
  • 虛線代表引用
  • 菱形代表基本值
徹底深刻了解js原型鍊之prototype,__proto__以及constructor(二)
  1. 原型鍊是單鍊,隻往一個方向流向,沒有回路
  2. 隻有Function的__proto__指向自己的prototype,這也向我們解釋了為什麼Function.prototype類型是function
  3. 我們通過__proto__隻能擷取到原型對象中的方法和屬性,是以persion1通過原型鍊是擷取不到Persion的myName屬性,但是我們可以通過原型對象的constructor來擷取或者修改Persion的屬性(這點太給力了)
請注意,有時候這個方法也不好使,因為原型對象的constructor是可以改變的,不一定指向原型對象所在的函數對象

繼續上面的例子:

persion1.__proto__.constructor.myName="我變了耶!";
console.log(Persion.myName); //我變了耶           
  1. 普通對象的_proto__一定指向創造它的函數對象的prototype
  2. 原型對象的__proto__一定指向Object.prototype!
  3. 通過圖我們可以簡單了解,擁有原型對象屬性的對象是函數對象,否則為普通對象
  4. 原型鍊是有開始和盡頭的,開始于null,結束于普通對象
  5. 所有的函數對象都是Function以new的方式創造出來了,包括Function自己且每個函數對象的__proto__都指向了Function.prototype
  6. Object是所有對象的父類,我們也可以稱之為基類,不過不要糾結于叫什麼,因為我們通過圖可以看到每一個對象(不管是原型對象還是普通對象還是函數對象)的通過原型鍊都可以引向Object.prototype

以上九條我稱為原型鍊之九句真言(不要太在意名字,我自己随便起的 ~)

意外收獲:this.name和this.job難道不應該在Persion中也有一份嗎?無數個日夜,愚笨的部落客對this的用法都不甚了解,直到我畫出了這種圖,我tm徹底明白了this的含義,就是誰運作包含this的這個函數,this就把挂在它身上的包袱(屬性)甩給誰!

看到了嗎,persion1調用了Persion,那麼自然多了2個屬性,但是注意,name跟job并不是Persion的屬性!!

思考:圖中沒有畫出Object.__proto__的指向,請問他指向哪?(請隻依據九句真言解答)

思考題解答

思考:判斷下清單達式傳回的值:

perison1.__proto__===Persion.prototype;           
首先判斷perison1是通過new方式被Persion創造出來的,依據九句真言第4條得出 :true
perison1.name===Persion.name;           
通過關系圖可以看到不相等,我已經在意外收獲中解答了,答案為:false
perison1.prototype.__proto__===Object.prototype;           
隻看圖可以看到perison1沒有prototype,是普通對象是以答案為:js報錯~~
Persion.prototype.__proto__===Object.prototype;           
參考九句真言第5條:答案為:true
Persion.__proto__===Function.prototype;           
Persion為函數對象,參考九句真言第8條,答案為:true
Persion.constructor===perison1;           
Persion是由Function創造出來的是以Persion.constructor指向Function,答案為:false
Function.__proto__===Object.prototype;           
Function我們已經反複強調是由自身創造是以Function.__proto__===Function.prototype;,答案為:false
Function.prototype.__proto__===Object.prototype;           
根據九句真言第5條,答案為:true
typeof Persion.prototype;           

答案為:object

typeof Function.prototype;           

答案為:function,注意這個是比較特殊的原型對象

下面來分步解答

  1. Object屬于函數對象
  2. 依據九句真言第八條得出函數對象的__proto__都指向了Function.prototype
  3. 是以Object.__proto__===Function.prototype

這一點是不太好了解的,是Function創造了Object,然後Object創造了Function的原型對象prototype

是以就有了

Object.__proto__===Function.prototype
Function.prototype.__proto__===Object.prototype           

不要太糾結于此,隻要了解就好

結束語

好了,原型鍊的概念原理通過這2篇教程我相信大家已經滾瓜爛熟了!下面的教程,我們會着重研究下原型鍊在實際的應用!

作者:宜信技術學院 劉曉敏

繼續閱讀