怎麼深刻理解 new 操做符

和其餘高級語言同樣 JavaScript 也有 new 操做符,咱們知道 new 能夠用來實例化一個類,從而在內存中分配一個實例對象。 但在 JavaScript 中,萬物皆對象,爲何還要經過 new 來產生對象? 帶着這個問題,咱們一步步來分析和理解 new 的一些特性:app

一、認識 new 操做符函數

function Animal(name){
    this.name = name;
}
 Animal.color = "black";
 Animal.prototype.say = function(){
    console.log("I'm " + this.name);
 };
 var cat = new Animal("cat");
 --------------------------------------------
 console.log(
     cat.name,  //cat
     cat.height //undefined
 );
 cat.say(); //I'm cat
 ----------------------------------------------
 console.log(
     Animal.name, //Animal
     Animal.color //back
 );
 Animal.say(); //Animal.say is not a function
 
代碼解讀以下:
this

  L1-3: 建立了一個函數Animal,並在其 this 上定義了屬性:name,name的值是函數被執行時的形參。
  L4 : 在 Animal 對象(Animal自己是一個函數對象)上定義了一個靜態屬性:color,並賦值「black」
  L5-7:在 Animal 函數的原型對象 prototype 上定義了一個 say() 方法,say方法輸出了 this 的 name 值。
  L8: 經過 new 關鍵字建立了一個新對象 cat
  L10-14: cat 對象嘗試訪問 name 和 color 屬性,並調用 say 方法。
  L16-20: Animal 對象嘗試訪問 name 和 color 屬性,並調用 say 方法。
  
  
  
二、剖析 new 的內部原理
prototype

 第8行代碼是關鍵: 
var cat = new Animal("cat");
Animal 自己是一個普通函數,但當經過new來建立對象時,Animal 就是構造函數。
對象

JS引擎執行這句代碼時,在內部作了不少工做,用僞代碼模擬其內部流程以下:繼承

new Animal("cat") = {
 
    var obj = {};
 
    obj.__proto__ = Animal.prototype;
 
    var result = Animal.call(obj,"cat");
 
    return typeof result === 'object'? result : obj;
}
ip

將上述流程分爲 4 個步驟來理解:內存

【1】建立一個空對象 obj;原型鏈

【2】把 obj 的__proto__ 指向構造函數 Animal 的原型對象 prototype,此時便創建了 obj 對象的原型鏈:obj->Animal.prototype->Object.prototype->nullget

【3】在 obj 對象的執行環境調用 Animal 函數並傳遞參數 「 cat 」 。 至關於 var result = obj.Animal("cat")。

         當這句執行完以後,obj 便產生了屬性 name 並賦值爲 "cat"。關於 call 的用法請參考:深刻理解 call、apply 和 bind

【4】考察第 3 步的返回值,若是無返回值 或者 返回一個非對象值,則將 obj 做爲新對象返回;不然會將 result 做爲新對象返回。

 

根據以上過程,咱們發現 cat 其實就是【4】的返回值,所以咱們對 cat 對象的認知就多了一些:

cat的原型鏈是:cat->Animal.prototype->Object.prototype->null
cat上新增了一個屬性:name
分析完了 cat 的產生過程,咱們再分析一下輸出結果:

cat.name : 在【3】中,obj 對象就產生了 name 屬性。所以 cat.name 就是這裏的 obj.name
cat.color:  cat 對象先查找自身的 color,沒有找到便會沿着原型鏈查找,在上述例子中,咱們僅在 Animal 對象上定義了 color,並無在其原型鏈上定義,所以找不到。
cat.say: cat會先查找自身的 say 方法,沒有找到便會沿着原型鏈查找,在上述例子中,咱們在 Animal 的 prototype 上定義了say,所以在原型鏈上找到了say 方法。
另外,在 say 方法中還訪問 this.name,這裏的 this 指的是其調用者 obj,所以輸出的是 obj.name 的值。

對於Animal來講,它自己也是一個對象,所以它在訪問屬性和方法時也遵照上述查找規則,因此:

Animal.color ->   " black "
Animal.name ->  " Animal " 
Animal.say() ->   Animal.say is not a function
須要注意的是,Animal 先查找自身的 name,找到了 name,但這個 name 並非咱們定義的 name,而是函數對象內置的屬性,通常狀況下,函數對象在產生時會內置 name 屬性並將函數名做爲賦值(僅函數對象)。

另外,Animal 在自身沒有找到 say() 方法,也會沿着其原型鏈查找,Animal 的原型鏈以下所示:
 Animal.__proto__
 function(){}
 Animal.__proto__ == Function.prototype
 true
 Function.prototype.__proto__ == Object.prototype
 true
 Object.prototype.__proto__
 null


 Animal 的原型鏈: Animal->Function.prototype->Object.prototype->null

 因爲 Animal 的原型鏈上也沒有定義 say 方法,所以返回異常提示。

三、探索 new 的真正意義
對 new 運算符有了較深刻的理解以後,咱們再回到開篇提到的問題:在JavaScript 中,萬物皆對象,爲何還要經過 new 來產生對象?

要弄明白這個問題,咱們首先要搞清楚 cat 和 Animal 的關係:

【1】cat 繼承了 Animal 對象
經過上面的分析咱們發現, cat 經過原型鏈繼承了 Animal 中的部分屬性,所以咱們能夠簡單的認爲:Animal 和 cat 是繼承關係。

【2】cat 是 Animal 的實例
cat 是經過 new 產生的對象,那麼 cat 究竟是不是 Animal 的實例對象? 咱們先來了解一下JS是如何來定義實例對象:

A instanceof B

若是上述表達式爲 true,JavaScript 認爲 A 是 B 的實例對象,咱們用這個方法來判斷一下cat 和 Animal

cat instanceof Animal; //true

從結果看,cat 確實是 Animal 實例,要想更加證明這個結果,咱們再來了解一下 instanceof 的內部原理:

var L = A.__proto__;
var R = B.prototype;
if(L === R)
    return true;
    
若是 A 的__proto__ 等價於 B 的 prototype,就返回true

在 new 的執行過程【2】中,cat 的 __proto__ 指向了Animal 的 prototype,因此 cat 和 Animal 符合 instanceof 的判斷結果。

所以,經過 new 建立的 對象 和 構造函數 之間創建了一條原型鏈,原型鏈的創建,讓本來孤立的對象有了依賴關係和繼承能力,讓JavaScript 對象能以更合適的方式來映射真實世界裏的對象,這是面向對象的本質。

四、實戰演練 
 下面是一個經典例子,涉及 new 、this、以及 原型鏈 相關問題,請看代碼:


function Foo(){
    getName = function(){
        console.log(1)
    }
    return this;
}
Foo.getName = function(){
    console.log(2)
}
Foo.prototype.getName = function(){
    console.log(3)
}
var getName = function(){
    console.log(4)
}
function getName(){
    console.log(5)
}
//output : ?
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();

 

相關連接:https://ke.qq.com/course/256212?flowToken=1001258

143046757

相關文章
相關標籤/搜索