原型和原型鏈的底層運行機制

原型prototype和原型鏈__proto__:
每一個類(函數)都具備prototype,並且屬性值是一個對象。
對象上天生具備一個屬性:constructor,指向類本身。
每一個對象(普通對象、prototype、實例、函數等)都具備:proto,屬性值是當前實例所屬類額原型。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>原型和原型鏈</title>
</head>

<body>
    <script>
        function Fn() { //在此中的內容都是給實例設置私有屬性
            this.x = 100;
            this.y = 200;
            this.getX = function () {
                console.log(this.x);
            }
        };
        Fn.prototype.getX = function () {
            console.log(this.x);
        };
        Fn.prototype.getY = function () {
            console.log(this.y);
        };
        let f1 = new Fn;
        let f2 = new Fn;
        console.log(f1.getX === f2.getX); //false 因爲f1和f2都有getX,但是都屬於自己私有屬性,是兩個不同的堆,所以爲false
        console.log(f1.getY === f2.getY); //true ,因爲f1和f2都沒有getY,會通過__proto__向上查找,找到Fn,prototype中的getY,指向同一個,所以相等
        console.log(f1.__proto__.getY === Fn.prototype.getY);//true,因爲f1.__proto__.getY 直接跳過f1,直接找到Fn.prototype中的getY,與Fn.prototype.getY指向的同一個,故相等
        console.log(f1.__proto__.getX === f2.getX);//false,因爲f1.__proto__.getX指向的是共有的Fn.prototype中的getX,而f2.getX是自己私有的,所以不相等。
        console.log(f1.getX === Fn.prototype.getX);//false,因爲f1.getX是自己私有的,而Fn.prototype.getX是共有的,所以不相等
        console.log(f1.constructor);//Fn ,f1中沒有constructor,通過__proto__向上找,所以找到Fn.prototype中的constructor,就是Fn
        console.log(Fn.prototype.__proto__.constructor);//Object,通過Fn.prototype.__proto__.,找到Object.prototype,constructor是Object,所以輸出Object
        f1.getX(); // 100,是調用f1的私有方法getX ,console.log(this.x);this指f1
        f1.__proto__.getX(); //undefined,因爲f1.__proto__.getX()指的是,Fn.prototype的getX,=> console.log(this.x); => this.x =>指向的f1.__proto__.x,在Fn.prototype中沒x,繼續向上找到Object.prototype也沒有x,所以爲undefined
        f2.getY();//200,f2中沒有getY,通過__proto__找到Fn.prototype中,有getY => console.log(this.y); =>this指向f2,所以爲200
        Fn.prototype.getY();//undefined,因爲 Fn.prototype.getY() => console.log(this.y) => this指的是 Fn.prototype.y,裏面沒有,繼續向上查找,直到找到Object.prototype,依舊沒有y,所以是undefined

        // Fn()把普通函數執行 Fn普通函數
        // new Fn; new Fn();都是創建類的實例,第二種可以傳遞實參 

    </script>
</body>

</html>

以上代碼解析:
只使用堆內存
Fn堆內存:
代碼字符串(當做普通函數):
“this.x = 100; this.y = 200; this.getX = function () { console.log(this.x); }”;
鍵值對(普通對象):
name:‘Fn’(函數名稱),
length:0(形參個數);
因爲每一個對象天生具有prototype,並且屬性值是一個對象,所以Fn的堆內存中海油如下屬性:prototype ,指向一個新的堆,可以稱爲Fn,prototype.

	Fn.prototype堆內容如下:(因爲在執行代碼時,會先找私有的內容,私有沒有,會根據__proto__尋找,因爲f1和f2是Fn的實例,所以,在f1和f2中找不到時,會找到此處,找所屬類原型上的,而這裏的內容相對於f1和f2,就是實例的共有屬性,若是相對於Fn的prototype就是私有屬性)
		因爲對象上天生具備一個屬性:constructor,指向類本身。所以此堆中含有如下內容:	constuctor:Fn(指向Fn本身)

每一個對象(普通對象、prototype、實例、函數等)都具備:proto,需要知道對象數據類型值都有哪些:普通對象、數組/正則/日期對象、實例、函數也是對象 => 萬物皆是對象。

代碼繼續向下運行:

Fn.prototype.getX = function(){
		console.log(this.x);
}
Fn.prototype.getY = function(){
		console.log(this.y);
}

=> 在Fn.prototype的堆內存中,添加getX和getY屬性,因爲是函數,所以也是新的堆內存
即在Fn.prototype堆內存中新加:
getX : function(){}新的堆地址
getY: function(){}新的堆地址

繼續向下運行:

let f1 = new Fn;
=>相當於創建Fn的一個實例,叫f1; 創建一個新的堆,可以稱爲f1的實例對象{堆}。
	new一個Fn,就是創建一個實例,並且執行Fn,而且Fn中的this都指向當前這個實例,也就是f1,內容有:
		this.x =100  => x:100,
		this.y =200  => y:200,
		this.getX=function(){}... => getX:function(){} 這是新的堆
		以上內容屬於f1的私有屬性。

代碼繼續運行:

let f2 = new Fn; 
	=>f2的實例對象,可以稱爲f2的實例對象{堆}:
	new一個Fn,就是創建一個實例,並且執行Fn,而且Fn中的this都指向當前這個實例,也就是f2,內容爲:
		this.x =100  => x:100,
		this.y =200  => y:200,
		this.getX=function(){}... => getX:function(){} 這是新的堆 , 與f1中的getX 都是簡單的函數
		以上內容屬於f2的私有屬性。

每一個對象(普通對象、prototype、實例、函數等)都具備:proto,屬性值是當前實例所屬類額原型。所以以上所說的哪個對象,無論是Fn的堆內存、Fn.prototype堆內存、f1的實例對象{堆}、還是f2的實例對象{堆},都具有__proto__這個屬性。
而這個屬性值都是指向所屬類的原型,f1和f2都是Fn的實例,所以Fn是f1和f2的所屬類,所以他們的__proto__都是指向Fn的原型,即Fn.prototype堆內存。
而Fn.prototype堆不是new誰出來的,那麼就是所有都是Object的實例。
Object是內置類{堆}, 內容爲:
函數:代碼字符串:[native code],瀏覽器看不到,底層是C和C++寫出來的
對象:鍵值對: name:“Object”,
length:1, …其他屬性
prototype:Object.prototype
proto

Object.prototype:是個對象,堆內存:裏面內容有
	constructor:Object
	hasOwnProperty:...
	toString:function(){}...等方法
	__proto__所有對象都有這個屬性,
Object的原型prototype指向Object.prototype。
如果知道是誰new出來的,__proto__就指向誰的原型,如果不知道,是個對象的話,__proto__就指向Object.prototype.所以Fn,prototype堆中的__proto__指向的就是Object.prototype。
**Object是基類,它prototype原型上的__proto__指向null(如果指向也是自己)。**

原型鏈__proto__:
先找自己私有的,沒有的話基於__proto__找所屬實例prototype上共有的屬性,再沒有繼續向上查找,一直找到Object.prototype爲止。

原型圖

原型與原型鏈

typeof Dog => function
所以函數是一個類,Function是一個堆,裏面的內容爲:
函數:
代碼字符串:[native code] 內置的原生代碼
對象:
鍵值對:
name:“Function”,
prototype:堆對象,Function.prototype
proto

Function.prototype:
constructor:Function
call/apply/bind
proto,不知道new誰的,都指向Object,所以Function.__proto__指向Object

Fn堆內存,和Object內置類{堆}本身是函數,所以就是function的實例,所屬類的原型指向的就是函數Function,所以Fn的堆內存的__proto__和Object內置類{堆}的__proto__都指向Function
Function 是Object的實例,因爲通過Function的原型鏈可以找到Object的原型,而且Object是Function的實例,因Object的原型鏈也可以找到Function的原型。是兩個基類,類是函數,函數也是對象。
Function的原型是一個函數:匿名空函數(但是我們要把它當做普通對象對待)
Function的原型與原型鏈

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章