在講原型之前,我們先說說js的數據類型,有一下幾種
原始數據類型:String、Number、Boolean、Null、undefined、Symbol(ES6)、BigInt(ES10)
引用類型:Object
JS 中 typeof 輸出分別是什麼呢?
1)基礎數據類型
typeof 'a' // 'string'
typeof 12 // 'number'
typeof false // 'boolean'
typeof null // 'object'
typeof NaN // 'number'
2)引用數據類型
typeof Object //'function'
typeof Number //'function'
typeof String //'function'
typeof Boolean //'function'
typeof Function //'function'
這個時候有人肯定會有疑問,爲啥引用類型這裏輸出的function,我們知道任何幾個結果的輸出都是有原因的,我們先在這裏埋下一個伏筆。接下來我們進入主題,講講原型
一、構造函數創建對象
我們先使用構造函數創建一個對象
function Person (name, age) {
this.name = name
this.age = age
}
var person = new Person('zbq', 28)
我們創建了一個Person構造函數,然後通過new來創建來一個實例person,接下來我們開始進入主題
prototype屬性
每個函數都有一個prototype屬性,指向實例原型,構造函數與實例原型的關係如下圖所示:
__proto__屬性
每個對象都有一個__proto__屬性,指向實例原型,該實例與實例原型的關係如下入所示
因此person的__proto__屬性與Person構造函數的prototype的屬性指向的是同一個實例原型 Person.prototype,我們來驗證一下
person.__proto__ === Person.prototype // true
補充說明:絕大部分瀏覽器都支持這個非標準的方法訪問原型,然而它並不存在於 Person.prototype 中,實際上,它是來自於 Object.prototype ,與其說是一個屬性,不如說是一個 getter/setter,當使用 obj.__proto__ 時,可以理解成返回了 Object.getPrototypeOf(obj)。
constructor屬性
我剛說了構造函數與實例原型的關聯,以及實例與實例原型的關聯,那實例原型與構造函數有啥關聯呢?這就是我們接下來要說的
實例原型的constructor屬性,它是指向構造函數的,我們用代碼驗證一下
Person.prototype.constructor === Person //true
它的關係圖如下所示:
接下來有人肯定要問了,那Person.prototype它有指向的是誰呢?這就是我們接下來要講的原型與原型之前的關聯了
二、原型與原型
前面我們說過每個對象都有一個__proto__屬性,而實例原型也不例外,它也有一個__proto__指向上一個實例原型對象,因此就有如下的Person.prototype.__proto__指向Object.prototype。
三、原型鏈
原型與原型之間通過__proto__建立的的關聯就是原型鏈(下圖的藍色線條),這裏再補充一下Object.prototype指向的原型是null
我們可以用代碼驗證一下
Person.prototype.__proto__ === Object.prototype // true
Object.prototype.__proto__ === null // true
四、拓展
我們先記住一個知識點,instanceof 它表示是一種繼承關係。然後我們再看看以下的一個例子
Object instanceof Function // true
Function instanceof Object // true
Function instanceof Function // true
肯定很多人一臉的疑惑,在想爲什麼?疑惑是正常的。不過我們先來一步步分析吧!
1、首先我們先看一個函數的創建
// 方式一:傳統方式來新建一個函數
function add1 (a, b) {
return a + b
}
// 方式二:通過new的方式來創建(平時不推薦使用)
var add2 = new Function ('a', 'b', 'return a + b')
根據此可以得出一個結論:
1) 函數也是對象,所以也有__prototype__屬性
2) Function是一個構造函數 function Function () {....}
關係圖如下:
2、創建對象
// 方式一:對象字面量的形式
var obj1 = {}
// 方式二:new方式來創建
var obj2 = new Object()
obj1.__proto__ === Object.prototype // true
obj2.__proto__ === Object.prototype // true
根據以上可以得出一個結論:
1) 對象字面量的創建方式只是new方式的一種快捷創建方式
2) Object也是一個構造函數 function Object () {...}
3) Object也是Function的一個實例
Object.__proto__ === Function.prototype // true
以上實例的關係圖如下:
所以你現在是不是能懂的爲啥以下的例子的結果都是返回true,以及開篇文章中 typeof Object === 'function'
Object instanceof Function // true
Function instanceof Object // true
Function instanceof Function // true
小結:
1、每個函數都有一個prototype屬性
2、每個對象都有一個__proto__屬性
3、任何函數皆對象
以上文章是參考至:
https://segmentfault.com/a/1190000008959943
https://www.cnblogs.com/wangfupeng1988/tag/%E5%8E%9F%E5%9E%8B