JavaScript深入淺出__proto__和prototype
首先我們先記住幾個知識點:
- 每個函數(shù)都有一個
prototype
屬性 - 每個對象都有一個
__proto__
屬性(null除外) - 函數(shù)也是對象
構造函數(shù)和實例
首先我們通過下面的例子了解些基本的概念
function Person() { } var person1 = new Person()
- 使用 new 創(chuàng)建對象的函數(shù)就是構造函數(shù)、創(chuàng)建出的對象就是構造函數(shù)的實例對象
- 本例中:Person 就是一個構造函數(shù),我們使用 new 創(chuàng)建了一個實例對象 person1
- 構造函數(shù)大寫只是約定俗成的習慣,實際上任何可以使用 new 運算符的函數(shù)都可以是構造函數(shù)
prototype
function Person() { } Person.prototype.name = 'Person' var person1 = new Person() console.log(person1.name) // Person console.log(Person.prototype)
- Person 的
prototype
屬性指向的是Person.prototype
的原型對象 - 在這個例子中可以看出,person1 本身并沒有 name 屬性,訪問的其實是 Person 中
prototype
的 name - 從這里可以得出必然有一種關系把
person1
和Person
關聯(lián)起來,使得person1可以訪問到Person中prototype的屬性值
帶著上面的疑問我們繼續(xù)下面的例子
__proto__
和prototype
的關系
function Person() { } Person.prototype.name = 'Person' var person1 = new Person() console.log(person1) console.log(person1.__proto__.name === Person.prototype.name) // true console.log(person1.__proto__ === Person.prototype) // true
一開始我們就提到,每個對象都有一個__proto__
屬性(null除外),通過這個例子我們發(fā)現(xiàn)person1的__proto__屬性下有個name屬性,正好是Person.prototype.name
的值,由此我們可以看出實例person1是通過__proto__訪問的構造函數(shù)Person的prototype屬性
根據(jù)上面的結論,我們很容易得出以下關系圖
由此我們很容易得出,多個示例對象之間通過__proto__
進行關聯(lián),可以通過__proto__
共享Person.prototype上的屬性
constructor
既然構造函數(shù)和實例都可以指向原型,那么原型是否有屬性指向構造函數(shù)或者實例呢? 通過上面的例子,我們發(fā)現(xiàn)除了__proto__
,還有一個constructor
屬性
function Person() { } Person.prototype.name = 'Person' var person1 = new Person() console.log(Person) // ? Person() {} console.log(Person.prototype.constructor) // ? Person() {} console.log(person1.__proto__.constructor) // ? Person() {} // 由此我們發(fā)現(xiàn)`constructor`屬性指向的是Person構造函數(shù)本身,不難得出以下結論 console.log(Person === Person.prototype.constructor) // true
由此我們可以得出以下關系圖:
原型對象的原型
- 原型也是一個對象,一開始就提到,每個對象都有一個
__proto__
屬性(null除外),因此原型對象也是有__proto__
的 - 實際上原型對象就是通過 Object 構造函數(shù)生成的
var prototypeObj = new Object() console.log(prototypeObj.__proto__ === Object.prototype) // true
到此我們可以得出一個新的關系圖
到這里大家可能就有疑惑了,這樣不就無限循環(huán)了嗎,Object.protoType
的__proto__
又是什么呢?
console.log(Object.protoType.__proto__) // null console.log(Object.protoType.__proto__ === null) // true
所以 Object.prototype 為null,屬性查找到這里也就結束了
原型鏈
由上面的例子我們得知,在查找對象的屬性時,優(yōu)先查找實例對象的屬性,查找不到時就會通過__proto__
查找 prototype
原型對象的屬性,還查不到會通過prototype的__proto__
繼續(xù)查找,直到Object.protoType.__proto__
為止
圖中由__proto__
組成的紅色鏈路就是我們所說的原型鏈
擴展知識
關于 Object 和 Function
既然函數(shù)也是對象,對象都有 __proto__
,那么 Object
和 Function
的 __proto__
屬性又是什么呢?
- Object對象是由Function構造函數(shù)創(chuàng)建的
- Function的原型對象
Function.prototype
是由Object構造函數(shù)創(chuàng)建的 - 【按照原型的定義,可以理解為】Function對象是由Function構造函數(shù)本身創(chuàng)建
根據(jù)原型鏈的相關知識,實例對象的 __proto__
指向構造函數(shù)的原型對象 prototype
// Object對象由Function構造函數(shù)創(chuàng)建 Object.__proto__ === Function.prototype // true // Function的原型對象`Function.prototype`是由Object創(chuàng)建 Function.prototype.__proto__ === Object.prototype // true // Function由Function本身創(chuàng)建(按照原型的定義可以簡單這么去理解,這里不做深究) Function.__proto__ === Function.prototype // true Object.getPrototypeOf(Function) === Function.prototype // true
由此我們可以得出最終的關系圖:
關于 getPrototypeOf
、isPrototypeOf
、instanceof
function Person() { } var person1 = new Person() // Object.getPrototypeOf(obj) 返回obj實例對象的原型(obj.__proto__) console.log(Object.getPrototypeOf(person1) === Person.prototype) // true // Object.isPrototypeOf(obj),如果obj.__proto__和Object.prototype在一條原型鏈上(或者理解為Object為obj的構造函數(shù)或父級構造函數(shù)),則返回true console.log(Object.prototype.isPrototypeOf(person1)) // true console.log(Object.prototype.isPrototypeOf(Person.prototype)) // true console.log(Person.prototype.isPrototypeOf(person1)) // true // (obj instanceof Object) 同isPrototypeOf類似,obj.__proto__和Object.prototype在一條原型鏈上,則返回true console.log(person1 instanceof Person) // true console.log(person1 instanceof Object) // true
總結
- 每個函數(shù)都有一個
prototype
屬性,值是一個原型對象 - 每個對象都有一個
__proto__
屬性(null除外),指向構造函數(shù)的原型prototype
- 構造函數(shù)的原型對象的
constructor
指向構造函數(shù)本身 - 原型對象是由
Object
構造函數(shù)實例化產(chǎn)生的,所以原型對象的__proto__
指向Object的原型對象Object.prototype
Object
構造函數(shù)的原型對象為null
function Person() {} var person = new Person() console.log(person.__proto__ === Person.prototype) // true console.log(Person === Person.prototype.constructor) // true console.log(Object.prototype.__proto__ === null) // true // 推導person.constructor等于person.__proto__.constructor等于Person.prototype.constructor console.log(person.constructor === Person.prototype.constructor) // true
到此這篇關于JavaScript深入淺出__proto__和prototype的文章就介紹到這了,更多相關JS proto 和 prototype內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
小程序中使用css var變量(使js可以動態(tài)設置css樣式屬性)
這篇文章主要介紹了小程序中使用css var變量,使js可以動態(tài)設置css樣式屬性,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-03-03event.currentTarget與event.target的區(qū)別介紹
event.currentTarget與event.target的區(qū)別想大家在使用的時候不是很在意,本文以測試代碼來講解它門之間的不同2012-12-12javascript中導出與導入實現(xiàn)模塊化管理教程
這篇文章主要給大家介紹了關于javascript中導出與導入實現(xiàn)模塊化管理的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-12-12