前置
原型是 JavaScript 巧妙的設(shè)計(jì),它非常容易理解。都 2020 年了,看完這篇希望你以后不需要再重復(fù)學(xué)習(xí) JavaScript
原型了。如有不當(dāng)之處,懇請(qǐng)指點(diǎn)一二!
單詞
下面是相關(guān)單詞及其翻譯,牢牢記住它們就成功一半了。
* constructor 構(gòu)造器
* proto & prototype 原型;雛形;最初形態(tài)
constructor
function Drink() {} const a = new Drink() console.log(a.constructor) // ?
Drink() {}
a 是由函數(shù) Drink 構(gòu)造而來(lái)的。
prototype
簡(jiǎn)單寫(xiě)點(diǎn)代碼,后面全是 console.log。
function f() { this.a = 1 this.b = 2 } const o = new f() f.prototype.b = 3
f.prototype.c = 4
o 是 new f() 返回的結(jié)果,不妨回顧一下當(dāng)執(zhí)行 new f() 時(shí), new 操作符對(duì)函數(shù) f 做了些什么事。
* 創(chuàng)建一個(gè)空對(duì)象(即{}): var obj = Object.create(null)。
* 鏈接該對(duì)象(即設(shè)置該對(duì)象的構(gòu)造函數(shù))到另一個(gè)對(duì)象(本函數(shù)), 這個(gè)空對(duì)象繼承其原型: obj.__proto__ = f.prototype。
* 使用指定的參數(shù)調(diào)用函數(shù) f,new Foo 等同于 new Foo(),也就是 f 不帶任何參數(shù)調(diào)用的情況; 將步驟 1 創(chuàng)建的對(duì)象作為 this
的上下文(將 this 綁定到新創(chuàng)建的對(duì)象 | f 函數(shù)中的 this 的指針替換成 obj) ,f.call(obj)。
* 如果該函數(shù)沒(méi)有顯式地在函數(shù)中寫(xiě) return,則返回 this。
對(duì)于一個(gè)函數(shù),如果不使用 new 操作它,它只是一個(gè)正常的函數(shù);使用 new 操作符僅僅改變了它的 this
指向且在函數(shù)內(nèi)部隱式地創(chuàng)建了一個(gè)對(duì)象,然后再稱(chēng)之為 “構(gòu)造函數(shù)”。僅此而已。
如果你對(duì)第三步中的操作有困惑,看幾個(gè)簡(jiǎn)單的例子:
設(shè)置構(gòu)造函數(shù) function f() { this.a = 1 this.b = 2 } f() console.log(f.constructor)
//? Function() { [native code] } function f() { this.a = 1 this.b = 2 } const o
= new f() console.log(o.constructor) // ? f() { // this.a = 1 // this.b = 2 // }
this指針替換 function f() { console.log(this) // window this.a = 1 this.b = 2 } f()
function f() { console.log(this) // f?{} this.a = 1 this.b = 2
console.log(this) // f?{a: 1, b: 2} } new f() 什么是call? const drink = { name:
'Coca Cola', color: 'black', price: '3.5', intro: function () {
console.log(`名稱(chēng):${this.name},顏色:${this.color},價(jià)格:${this.price}`) }, } const
computer = { name: 'Orange Juice', color: 'orange', price: '4', }
drink.intro.call(computer) //名稱(chēng):Orange Juice,顏色:orange,價(jià)格:4
確保上面的內(nèi)容你能十分清晰,否則不要進(jìn)行下面的內(nèi)容。
console.log(o.b) // 2
o 的值是通過(guò) new f() 得到的對(duì)象,this 指向這個(gè)對(duì)象,函數(shù)中給 this 添加了屬性 b 為其賦值為 2,并將他返回。所以 這里打印出 2。
f.prototype 是無(wú)法被訪問(wèn)到的,這種情況還被稱(chēng)之為 property shadowing ---屬性遮蔽。
console.log(o.c) // 4 console.log(o.__proto__.c) // 4 console.log(o.__proto__
=== f.prototype) // true
函數(shù)中并沒(méi)有給 this 添加 c 屬性并為其賦值 4,但是打印 o.c 返回 4。通過(guò)上文你已經(jīng)知道 constructor 是干什么的了:
console.log(o.constructor.prototype.b) // 3
o 是由函數(shù) f 構(gòu)造的,o.constructor 返回函數(shù) f,所以o.constructor.prototype === f.prototype,
f.prototype 返回什么呢?上面初始代碼中直接寫(xiě)好的,現(xiàn)在可以翻上去看看 f.prototype,所以
o.constructor.prototype.b 返回 3。查找對(duì)象上的屬性就是先找自身再通過(guò) __proto__ 一層一層往上找的:
* 如果自身有該屬性直接獲取它的值;
* 如果自身有且其構(gòu)造器的 prototype 上也有,屬性遮蔽不會(huì)忘了吧;
* 如果一直沿著 __proto__ 找但沒(méi)找到,會(huì)返回 undefined;為什么呢? console.log({}.constructor) // ?
Object() { [native code] } console.log({}.__proto__ === Object.prototype) //
true console.log(Object.prototype.__proto__) // null
看到這里,應(yīng)該十分清晰了。這就是最終為什么會(huì)返回 undefind 的原因:Object.prototype.__proto__ 指向 null。
小練習(xí)
做一個(gè)簡(jiǎn)單又不給你解釋的小練習(xí)吧!
console.log(o.b) console.log(o.__proto__.b) console.log(o.d) 答案 // 2 // 3 //
undefined
重要提示
對(duì)于 Object.prototype.__proto__:
測(cè)試代碼
如果看完還是不太明白,動(dòng)手試一試吧!我把本文用到的代碼片段放到此處供你快速拷貝。
function f() { this.a = 1 this.b = 2 } const o = new f() f.prototype.b = 3
f.prototype.c = 4 console.log(o.b) // 2 console.log(o.c) // 4
console.log(o.__proto__.c) // 4 console.log(o.__proto__ === f.prototype) //
true console.log(o.constructor.prototype.b) // 3 console.log(o.b) // 2
console.log(o.__proto__.b) // 3 console.log(o.d) // undefined
console.log({}.constructor) // ? Object() { [native code] }
console.log({}.__proto__ === Object.prototype) // true
console.log(Object.prototype.__proto__) // null // --------- other --------
console.log(o.__proto__) // {b: 3, c: 4, constructor: ?}
console.log(o.__proto__.__proto__ === Object.prototype) // true
console.log(Object.prototype.__proto__) // null
console.log(o.__proto__.__proto__.__proto__) // null
console.log(f.prototype.__proto__ === Object.prototype) // true
熱門(mén)工具 換一換
