前言
JS是一門面向?qū)ο蟮恼Z(yǔ)言晴及,在js有一種說(shuō)法,萬(wàn)物皆對(duì)象。本文將帶領(lǐng)大家深入了解JS對(duì)象的原型及原型鏈戴质。
PS:本文所有例子均使用ES6
規(guī)范描述。
對(duì)象
js中對(duì)象可分為兩大類:函數(shù)對(duì)象function
及普通對(duì)象object
踢匣,官方稱:ECMAScript 的函數(shù)實(shí)際上是功能完整的對(duì)象告匠。咱可以使用一個(gè)例子簡(jiǎn)短說(shuō)明這一點(diǎn)。
console.log(Function instanceof Object)
//輸出 true
首先离唬,在了解原型鏈之前后专,我們要提到3個(gè)東西
- constructor
- prototype
-
__proto__
首先,我們需要牢記兩點(diǎn):
①__proto__
和constructor
屬性是對(duì)象所獨(dú)有的输莺;
②prototype
屬性是:函數(shù)對(duì)象所獨(dú)有的戚哎。但是由于JS中函數(shù)也是一種對(duì)象,所以:函數(shù)對(duì)象也擁有__proto__
和constructor
屬性嫂用。
let a = {};
console.log(a.prototype); //undefined
console.log(a.__proto__); //Object {}
console.log(a.constructor); //function() {}
let b = function () { }
console.log(b.prototype); //b {}
console.log(b.__proto__); //function() {}
console.log(b.constructor); //function() {}
什么是 constructor型凳?
(constructor)構(gòu)造函數(shù)是一種特殊的函數(shù),用來(lái)在創(chuàng)建對(duì)象時(shí)初始化對(duì)象嘱函,如果我們不顯式聲明構(gòu)造函數(shù)甘畅,js會(huì)默認(rèn)構(gòu)造一個(gè)空的constructor
,在構(gòu)造函數(shù)中,我們可以為對(duì)象聲明默認(rèn)值疏唾。
下方案例中添加了一個(gè)名叫a
的字符串類型(this
在這兒指向的是test
)
例:
class test {
constructor(){
this.a = ''
}
}
那構(gòu)造函數(shù)的返回值又是什么?我們又能否修改構(gòu)造函數(shù)的返回值?
眾所周知蓄氧,構(gòu)造函數(shù)的調(diào)用方式是 new
關(guān)鍵字,我們要調(diào)用test
的構(gòu)造函數(shù)就使用:
let t = new test();
而此時(shí),t
的值就是構(gòu)造函數(shù)返回的值槐脏,也就是test
對(duì)象實(shí)例,也就是this
(默認(rèn)返回this,而this指向該內(nèi)存空間)喉童。
那我們?nèi)绾胃臉?gòu)造函數(shù)的返回值呢?
class test {
constructor(){
this.a = '';
return 1
}
}
這樣能否把1返回回去呢?答案是不可以顿天,constructor
必須返回一個(gè)對(duì)象泄朴,也就是一個(gè)引用類型,如果我們這樣:
class test {
constructor(){
this.a = '';
return {
}
}
}
是能夠正常返回的露氮,此時(shí)t
就是返回的{}
空對(duì)象祖灰。
將我們創(chuàng)建的新實(shí)例打印出來(lái)我們會(huì)發(fā)現(xiàn)這個(gè)屬性__proto__
。
什么是 __proto__?
__proto__
并不是__proto__
,是不是有點(diǎn)繞畔规?簡(jiǎn)而言之局扶,__proto__
屬性是瀏覽器為我們實(shí)現(xiàn)的一個(gè)屬性,它并不存在于js中叁扫,在未實(shí)現(xiàn)__proto__
屬性的瀏覽器中是無(wú)法看見的三妈,它在js中表現(xiàn)的樣子是[[Prototype]]
上文說(shuō)到__proto__
屬性是對(duì)象獨(dú)有的,我們舉個(gè)栗子說(shuō)明下__proto__
到底是啥
//定義類型 人類
class Human {
constructor() {
this.type = '碳基生物'
}
}
//定義類型 女人
class Woman extends Human {
constructor() {
super();
this.sex = '女'
}
}
//定義類型 女孩
class girl extends Woman {
constructor() {
super();
this.age = 16;
}
}
let human = new Human();
let woman = new Woman();
let g = new girl();
console.log(human, woman, g);
大家發(fā)現(xiàn)一個(gè)規(guī)律沒(méi)莫绣?每個(gè)對(duì)象的
__proto__
都指向了另一個(gè)對(duì)象畴蒲,也可以稱為指向了它的父對(duì)象的原型對(duì)象!嘿嘿,從此次案例可以看出來(lái),JavaScript的
extends
本質(zhì)上還是對(duì)原型鏈的繼承以下代碼等同于上面代碼:
function Human() {
this.type = '碳基生物'
}
function Woman() {
this.sex = '女'
}
function girl() {
this.age = '16'
}
let human = new Human();
Woman.prototype = new Human();
let woman = new Woman();
girl.prototype = new Woman();
let g = new girl();
console.log(human, woman, g.type );
雖然在girl實(shí)例的直接屬性中并沒(méi)有
type
屬性对室,但在代碼最后依然能夠輸出此字段模燥。這就是__proto__
屬性存在的意義,當(dāng)訪問(wèn)一個(gè)對(duì)象的屬性時(shí),如果該對(duì)象內(nèi)部不存在這個(gè)屬性掩宜,那么就會(huì)去它的__proto__
屬性所指向的那個(gè)對(duì)象(可以理解為父對(duì)象)里找蔫骂,如果父對(duì)象也不存在這個(gè)屬性,則繼續(xù)往父對(duì)象的__proto__
屬性所指向的那個(gè)對(duì)象(可以理解為爺爺對(duì)象)里找牺汤,如果還沒(méi)找到辽旋,則繼續(xù)往上找…直到null
,此時(shí)還沒(méi)找到檐迟,則返回undefined
由以上這種通過(guò)
__proto__
屬性來(lái)連接對(duì)象直到null
的一條鏈即為我們所謂的原型鏈补胚。
什么是 prototype?
上文提到,它是函數(shù)對(duì)象所特有的屬性追迟,它代表了當(dāng)前函數(shù)的原型對(duì)象
也就是說(shuō)溶其,在使用new
關(guān)鍵字時(shí),__proto__
所指向的,就是父對(duì)象的prototype
怔匣。
這個(gè)關(guān)系可以換算成公式:
__proto__ === constructor.prototype
或者說(shuō) g.__proto__ === girl.prototype
還是上個(gè)栗子說(shuō)明:
//定義類型 人類
class Human {
constructor() {
this.type = '碳基生物'
}
}
//定義類型 女人
class Woman extends Human {
constructor() {
super();
this.sex = '女'
}
}
//定義類型 女孩
class girl extends Woman {
constructor() {
super();
this.age = 16;
}
}
let human = new Human();
let woman = new Woman();
let g = new girl();
console.log(human.__proto__ === Human.prototype); //true
console.log(woman.__proto__ === Woman.prototype); //true
console.log(g.__proto__ === girl.prototype); //true
總結(jié)
constructor
握联,prototype
,__proto__
三者的關(guān)系?
prototype
和constructor
是函數(shù)對(duì)象的基礎(chǔ)屬性constructor
對(duì)象屬于函數(shù)對(duì)象的prototype
屬性每瞒,但它又指向函數(shù)對(duì)象本身__proto__
學(xué)名叫[[Prototype]]
,它指向父對(duì)象的prototype
,是連接父對(duì)象的橋梁
下面有栗子說(shuō)明原型鏈:
//定義類型 人類
class Human {
constructor() {
this.type = '碳基生物'
}
}
let human = new Human();
console.log(human.__proto__ === Human.prototype); //true
console.log(Human.__proto__ === Function.prototype); //true
console.log(Human.__proto__.__proto__ === Object.prototype); //true
console.log(Human.__proto__.__proto__.__proto__ === null); //true