__proto__(先後都是兩條槓)
prototype
constructor
普通對象
函數對象
構造器(構造函數)
實例(實例是個普通對象)
原型
原型對象
ps:第一次認真梳理知識點,有點淺顯,但願讀完你所收穫。若有錯誤,也望及時指出,感激涕零!
複製代碼
每一個對象都有__proto__ ,而prototype只有函數對象纔有
複製代碼
答:__proto__
上圖中: obj.__proto__ === Object.prototype
複製代碼
首先 Object.prototype叫作obj的原型對象,這個對象裏包含了全部對外共享的屬性和方法。面試
舉個例子:數組
var function Person(name){
this.name = name;
}
var p1 = new Person('林蛋大');
console.log(p1.__proto__); //Person.prototype
console.log(p1.__proto__ === Person.prototype); //true
複製代碼
其次,咱們在控制檯看到了很眼熟很扎眼的 constructor,它是什麼鬼?
複製代碼
如下寫法同 Person.prototype.constructor 直觀地用數學思惟理解:等號兩邊寫誰都同樣bash
console.log(p1.__proto__.constructor ); //Person
複製代碼
也就是說,原型對象裏有一個叫constructor的屬性,它指向本身的構造器(構造函數) 因此,通常用constructor屬性來獲取當前對象的構造函數app
以下:函數
p1.constructor === p1.__proto__.constructor
p1.constructor === Person.prototype.constructor
用數學思惟左右置換,互求,是能夠的
複製代碼
p1這個對象是Person的一個實例,由於它是Person new 出來,Person是它的構造器,因此它的constructor指向了Person;ui
另外,Person.prototype是一個對象,它的constructor也指向了Person,是否是能夠理解爲:Person.prototype 也是Person的一個實例?this
經過__proto__能夠獲取原型,一直往一層層獲取,一直__proto__直到結果爲null就是盡頭了。走完這個流程就是走完了你當前對象的原型鏈。(這一塊後面細講)編碼
經過constructor能夠獲取當前對象的構造函數spa
通俗的理解----prototype
function Person(name) {
this.name = name
}
// 修改原型
Person.prototype.getName = function() {}
var p = new Person('林蛋大')
console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__ === p.constructor.prototype) // true
// 重寫原型
Person.prototype = {
getName: function() {}
}
var p = new Person('楚中天')
console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__ === p.constructor.prototype) // false
why false????
複製代碼
這是由於給Person.prototype賦值的是一個對象直接量{getName: function(){}},使用對象直接量方式定義的對象,它的構造器(constructor)指向的是根構造器Object
因此這個時候p.constructor === Object爲true,它如今的構造器是個叫作Object的構造器(構造函數),而已經不是叫作Person的構造器了,你讓他們怎麼相等?這種繼承註定會失敗
那麼怎麼辦?這個時候要改很簡單,只要把constructor給指回來就行了,這是寫原型繼承的時候最最最重要的坑!
Person.prototype = {
getName: function() {}
}
var p = new Person('jack')
p.constructor = Person; //就是這一行,核心重點
!
console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__ === p.constructor.prototype) // true
複製代碼
上節說到__proto__能夠獲取原型對象,一直往上獲取就能拿到整條鏈子,怎麼個獲取法?口說不清咱們直接看代碼:
var function Person(name){
this.name = name;
}
var p1 = new Person('林蛋大');
//不打印的話,你知道如下會輸出什麼嗎?
1. p1.__proto__ ?
2. Person.__proto__ ?
複製代碼
你先把這圖放腦子裏等着,咱們先來分析第2題,:
p1.__proto__ ? Person.prototype
p1.__proto__.__proto__?
複製代碼
綜上所述,第2題要求的是p1的構造器的原型對象。 答案以下:
Person.prototype.__proto__ ?Object.prototype
騷問法:
p1.__proto__.__proto__ ?Object.prototype
變態問法:
p1.constructor.__proto__ ? Object.prototype
p1.__proto__.constructor.prototype.__proto__ ? Object.prototype
Person.prototype.constructor.prototype.__proto__ ? Object.prototype
暈了?請翻到上面兩個constructor的等式,左右置換一下:
p1.__proto__.constructor 就是Person
Person.prototype.constructor 就是Person
懂了吧?嘿嘿~
複製代碼
第2題分析完了,咱們來看看鏈子怎麼求。
咱們往上追溯原型鏈的目的,無非就是找些方法或者屬性來知足當前的coding須要,因此---
由 p1.__proto__ 獲得 Person.prototype,發現構造器Person的集合裏沒有咱們想要的
複製代碼
由 Person.__proto__ 獲得 Function.prototype,發現構造器Function的集合裏仍是沒有
複製代碼
由 Function.__proto__ 獲得 Object.prototype,發現構造器Object的集合裏仍是沒有
複製代碼
由 Object.__proto__ 獲得 null,納尼????
複製代碼
祖宗十八代找遍,都找到類人猿了,仍是沒有找到咱們要用的方法或者屬性,只有一個解釋:你要找的傢伙還沒有出世(不存在)。
打個比方就是p1的家族世代修煉,每一代都修煉出本身的獨門絕學,而後傳給後代,最後面的p1就繼承到了以上全部祖宗的絕學(屬性和方法)
console.log(p1.arguments) // arguments 從哪裏來的?
console.log(Person.call(window)) // call 方法從哪裏來的?
複製代碼
console.log(Function.prototype) // function() {} (一個空的函數)
console.log(Object.getOwnPropertyNames(Function.prototype));
/* 輸出
["length", "name", "arguments", "caller", "constructor", "bind", "toString", "call", "apply"]
*/
複製代碼
順利被咱們找出arguments和call,getOwnPropertyNames是頂級公民Object.prototype裏的屬性和方法,全部的對象都能繼承到它的屬性和方法,它的角色至關於老祖宗(初代)你們自行打印一下,它的方法和屬性很是多。
可是!Function.prototype竟然是個空函數,爲何?請看下一節
先無論它是空函數什麼的,來看看下列JS世界中各種構造器的原型,你會很驚訝他們都是同一個:
Number.__proto__ === Function.prototype // true
Number.constructor == Function //true
Boolean.__proto__ === Function.prototype // true
Boolean.constructor == Function //true
String.__proto__ === Function.prototype // true
String.constructor == Function //true
// 全部的構造器都來自於Function.prototype,甚至包括根構造器Object及Function自身
Object.__proto__ === Function.prototype // true
Object.constructor == Function // true
// 全部的構造器都來自於Function.prototype,甚至包括根構造器Object及Function自身
Function.__proto__ === Function.prototype // true
Function.constructor == Function //true
Array.__proto__ === Function.prototype // true
Array.constructor == Function //true
RegExp.__proto__ === Function.prototype // true
RegExp.constructor == Function //true
Error.__proto__ === Function.prototype // true
Error.constructor == Function //true
Date.__proto__ === Function.prototype // true
Date.constructor == Function //true
複製代碼
以下
Math.__proto__ === Object.prototype // true
Math.construrctor == Object // true
JSON.__proto__ === Object.prototype // true
JSON.construrctor == Object //true
複製代碼
上面說的函數對象固然包括自定義的。以下
// 函數聲明
function Person() {}
// 函數表達式
var Perosn = function() {}
console.log(Person.__proto__ === Function.prototype) // true
console.log(Man.__proto__ === Function.prototype) // true
複製代碼
這些打印結果說明:全部的構造器(構造函數)都來自於 Function.prototype,甚至包括根構造器Object及Function自身。因此全部構造器都繼承了Function.prototype的屬性及方法。 故,函數是惟一一個typeof 結果是function 的類型。
那麼上一節的問題,說Function.prototype怎麼是個空函數啊?不止是它,若是你求Array構造器的原型,也是一個空數組:
console.log(Function.prototype) // function() {} (一個空的函數)
console.log(Array.prototype) // [ ] (一個空的數組)
複製代碼
怎麼辦?故技重施啊!它本身沒有,它的原型確定有鴨!
//首先 Function.prototype/Array.prototype是個對象
console.log(Function.prototype.__proto__ === Object.prototype ) //true
console.log(Array.prototype.__proto__ === Object.prototype ) //true
//Object.prototype的原型呢?null,到世界的盡頭了
console.log(Object.prototype.__proto__ === null )//true
複製代碼
若是 Object.prototype.__proto__ === Function.prototype 爲true,
那麼繼續往上找 Function.prototype.__proto__ === Object.prototype
再繼續往上 Object.prototype.__proto__ === Function.prototype
再再繼續往上 Function.prototype.__proto__ === Object.prototype
.........
複製代碼
function Person(name) {
this.name = name
}
var p2 = new Person('king');
核心點:__proto__是求原型對象的,也就是求構造器的prototype屬性 ===>原型對象是構造器的一個屬性,自己是個對象
constructor 是求構造器的 ====> 構造器的prototype屬性的對象集合裏也有constructor,這個prototype裏的constructor指向構造器本身
console.log(p2.__proto__)//Person.prototype
console.log(p2.__proto__.__proto__)//結合上題,也就是Person.prototype的__proto__,Person.prototype自己是個對象,因此這裏輸出:Object.prototype
console.log(p2.__proto__.__proto__.__proto__)//同理,這裏是求Object.prototype的__proto__,這裏輸出:null
console.log(p2.__proto__.__proto__.__proto__.__proto__)//null後面沒有了,報錯
console.log(p2.__proto__.__proto__.__proto__.__proto__.__proto__)//null後面沒有了,報錯
console.log(p2.constructor)//Person
console.log(p2.prototype)//undefined p2是實例對象,不是函數對象,是沒有prototype屬性滴
console.log(Person.constructor)//Function 一個空函數
console.log(Person.prototype)//打印出Person.prototype這個對象裏全部的方法和屬性
console.log(Person.prototype.constructor)//Person
console.log(Person.prototype.__proto__)//Person.prototype是對象,因此輸出:Object.prototype
console.log(Person.__proto__)//Function.prototype
console.log(Function.prototype.__proto__)//Object.prototype
console.log(Function.__proto__)//Function.prototype
console.log(Object.__proto__)//Function.prototype
console.log(Object.prototype.__proto__)//null
複製代碼