【JS】對於__proto__、protoType、constructor的理解
這三個屬性在js底層中經常用到,經常不知道其甚至,甚至老是把前兩張搞混淆。今天主要記錄下這三者的作用和用法。
在開始之前,我們先約定一些名詞,如下:
【函式】,即我們通常用Function 或者Class 定義的
【物件】,即Function或Class的例項,
特例,其實不管是Function還是 Class 其實都是特殊的Object,即 也是物件。
下面進入主題,我們調整下順序“”先介紹 constructor:
【constructor】從字面意思理解,constructor 為建造者、創造者。js的constructor也是這個意思,即物件的constructor屬性指向該物件的建造者.
由上可知:物件s 是有Son建立而來的,而Son則是由Function建立而來的。
另外,有字面constructor的字面意思,可以知道constructor一般指向js的基礎資料型別+Function,即:Number、String、Boolean、undefined、object、Null 但其中NUll 和undefined 是資料型別為止,所以是沒有創造者的 ,其產生的物件也就沒有constructor屬性。
所以:constructor要麼指向如實幾種資料型別,要麼指向Function(含Function的實現,如各種自定義類,以及Date ,Array 因為 Date、Array的constructor執向Function)
【prototype】 是函式特有的屬性,表示:函式的原型物件,官方解釋是:所有的 JavaScript 物件都會從一個 prototype(原型物件)中繼承屬性和方法。這句話咋一看很難理解。我們換一種方式就好理解了:
1、所有函式聲明後,都會自動隱形宣告一個屬性 prototype。預設的prototype指向一個物件,這個物件我們稱之為“原型物件”,函式預設原型物件的構造器屬性執向這個函式本身。
這個原型有什麼用呢?說到這裡相信大家都有聽過這個名詞吧“原型鏈”,不錯由於每個函式都有prototype屬性,有繼承關係的父子類,或者多層繼承關係的類之間通過prototype形成了原型鏈。
這樣做的作用是什麼呢?當我們去訪問一個物件的某個方法或者屬性的時候,js最先會在構建這個物件的 函式(類)上查詢是否含有該屬性(或方法),如果則找到則返回並預備使用;如果沒有,則回去這個函式的原型物件上去查詢,如果則找到則返回並預備使用,如果沒有找打則繼續向上層原型物件找查詢,知道原型物件放回Function為止。此時如果還沒找到則返回 undefined(如果查詢的方法,由於我們一般是這樣寫的:obj.xxx() 這樣寫表示查詢並執行方法,如果沒有xxx方法 執行的時候 就會報錯)
所以,物件的屬性、方法,來自構造其函式的定義和此函式的原型以及原型鏈。
舉例一:物件的屬性、方法,可以來之其構造的函式
這裡物件f的屬性"Test",來自構造f物件的函式F。 我們想所有F構建出來的物件多一個Addr屬性,通常我們可以修改F函式的定義
舉例二:物件的屬性方法,可以來自構造其函式的原型
舉例三:物件的屬性和方法,可以來自構造其函式的原型鏈
題外話,ES6中class定義的方法,就是往其prototype中新增方法實現的。
最後一個是【__proto__】,__proto__最好理解:所有物件都會自動建立一個屬性__proto__,這個屬性指向構建這個物件的函式的原型。
p.__proto__==p.constructor.prototype
所以往物件的__proto__新增屬性和方法,新增後再從構造這個物件的函式建立的物件就具備這些新的屬性和方法了(等價於直接往函式的原型中新增方法和屬性)
此文結束,這下你對constructor,prototype、__proto__認識清晰了嗎? 那試試下面幾道測試題,試試現在你的理解是否正確?
function Say(name, age) { this.name = name; this.age = age; } var person = new Say('jone', 30); console.log(person instanceof Say); console.log(person.__proto__ === Say.prototype); console.log(person.__proto__.constructor === Say.prototype.constructor); var obj = {}; console.log(obj.__proto__ == Object.prototype) var fn = function() {}; console.log(fn.__proto__ === Function.prototype);