關於Javascript中的new運算符,構造函數與原型鏈一些理解

原创 Lin_Grady 教程 javascript/jQuery 88阅读 2018-01-24 16:05:39 举报

文章主要基於<Javascrpt 高級程序設計3>總結的!!!

new constructor():創建一個用戶定義的對象類型的實例或具有構造函數的內置對象類型之一

構造函數(constructor):一個指定對象實例的類型的函數。
傳參(arguments):一個用來被構造函數調用的參數列表,在不傳遞任何參數的情況new Person可以省略括號。
構造函數與其他函數的唯一區別,就在於調用它們的方式不同。任何函數,只要通過 new 操作符來調用,那它就可以作為構造函數;而任何函數,如果不通過 new 操作符來調用,那它跟普通函數也不會有什麼兩樣。使用構造函數的主要問題,就是每個方法都要在每個實例上重新創建一遍。

這是基本用法,大家都懂的,然後我們往深層次裏挖掘下底層原理怎麼運作的.
假設有個函數
javascript 代碼

當代碼執行時會經過幾個步驟:
1,一個繼承自Person.prototype的新對象被創建;
2,創建執行的時候,將構造函數的作用域賦給新對象(因此 this 就指向了這個新對象);
3,執行構造函數中的代碼(為這個新對象添加屬性)等初始化工作。
4,如果構造函數返回了一個“對象”,那麼這個對象會取代整個new出來的結果。如果構造函數沒有返回對象,那麼new出來的結果為步驟1創建的對象,(ps:一般情況下構造函數不返回任何值,如果想覆蓋這個返回值,可以選擇返回一個普通對象。)

下面詳細舉例
1、如果構造函數不返回任何值則按照其他語言一樣返回實例化對象(即步驟1創建的對象)。

2、如果構造函數返回的是基本類型(string,number,boolean,null,undefined)也按照其他語言一樣返回實例化對象(即步驟1創建的對象).如果你們還搞不懂基本類型跟引用對象的區別,(可以瀏覽我之前寫的關於javascript基本類型和引用類型小知識)

3、若返回值是引用類型,則實際返回值為這個引用類型。

初學者特別應該注意的是他們之間是不同的,所謂構造函數是創建一個用戶定義的對象類型的實例或具有構造函數的內置對象類型之一
正常來說構造函數不需要有返回值的,可以認為構造函數和普通函數的最大差別就是:構造函數中沒有return語句,普通函數可以有return語句;構造函數中會使用this關鍵字定義成員變量和成員方法,普通的函數不會使用this關鍵字定義成員變量和方法。
像第二種情況即使返回基本類型也會被忽略掉,只有選擇返回一個普通對象才會取代整個new出來的結果

從這裏引出兩個關鍵知識點:
1, 所有對象都有屬性__proto__指向該對象的構造函數的原型對象,原型鏈就是靠它形成的;
2, 函數對象除了__proto__,還有屬性prototype指向該方法的原型對象,它的作用是:構造函數實例化對象的時候,告訴構造函數新創建的對象的原型是誰;

在javascript中, 通過new可以產生原對象的一個實例對象,而這個實例對象繼承了原對象的屬性和方法。因此,new存在的意義在於它實現了javascript中的繼承,而不僅僅是實例化了一個對象!
然後如果你想給函數實例定義一些屬性方法時,不能綁在函數本身上,因為那只是相當於給函數添加一個靜態屬性,即使你意圖添加的是一個方法

可以看出實例中沒有繼承到定義在構造函數上的方法屬性,為了實現需求,下面引出----------

理解原型對象(關鍵詞prototype, constructor, __proto__ )
無論什麼時候,只要創建了一個新函數,就會根據一組特定的規則為該函數創建一個 prototype屬性,這個屬性指向函數的原型對象。在默認情況下,所有原型對象都會自動獲得一個 constructor(構造函數)屬性,這個屬性包含一個指向 prototype 屬性所在函數的指針。就拿前面的例子來說,Person.prototype.constructor 指向 Person 。而通過這個構造函數,我們還可繼續為原型對象添加其他屬性和方法。創建了自定義的構造函數之後,其原型對象默認只會取得 constructor 屬性;至於其他方法,則都是從 Object 繼承而來的。當調用構造函數創建一個新實例後,該實例的內部將包含一個指針(內部屬性),指向構造函數的原型對象。ECMA-262 第 5 版中管這個指針叫 [[Prototype]] 。雖然在腳本中沒有標準的方式訪問 [[Prototype]] ,但 Firefox、Safari 和 Chrome 在每個對象上都支持一個屬性__proto__ ;而在其他實現中,這個屬性對腳本則是完全不可見的。不過,要明確的真正重要的一點就是,這個連接存在於實例與構造函數的原型對象之間,而不是存在於實例與構造函數之間。

簡單說構造函數、原型和實例的關係:每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。
我們創建的每個函數都有一個 prototype (原型)屬性,這個屬性是一個指針,指向一個對象,而這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法。如果按照字面意思來理解,那麼 prototype 就是通過調用構造函數而創建的那個對象實例的原型對象。使用原型對象的好處是可以讓所有對象實例共享它所包含的屬性和方法。換句話說,不必在構造函數中定義對象實例的信息,而是可以將這些信息直接添加到原型對象中.所以上面的答案是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法
Javascript 一切皆對象(普通對象和函數對象)。每個函數對象都有一個內部鏈接到另一個對象它的原型 prototype。該原型對象有自己的原型,等等,直到達到一個以null為原型的對象。根據定義,null沒有原型,並且作為這個原型鏈 prototype chain中的最終鏈接。

例如:

上面一步一步挖到最初的原型,有個注意的點容易混淆的,再強調一遍prototype是函數對象繼承的原型,__proto__是指向創建它的函數對象的原型對象prototype。,衹有真的弄清楚關係你才知道下面的區別
javascript 代碼

訪問一個對象的屬性時,它先在該對象上搜尋,如果該對象沒有就搜尋該對象的原型,如果還沒有就繼續往該對象的原型的原型搜索,依此層層向上搜索,直到找到一個名字匹配的屬性或到達原型鏈的末尾(即undefined)位置。

原型對象除了__proto__之外還有一個constructor屬性,作用是返回對創建此對象的數組函數的引用。這個比較簡單,直接上實例

實例化對象man打印結果如下.
man.__proto__.constructor === Person

關於Javascript中的new運算符,構造函數與原型鏈一些理解

评论 ( 1 )
最新评论
HaiMianBoBo 2018-01-25 15:01:33 1F

繁体字看的好难受 ,老铁