原型鏈?zhǔn)菫榱藢?shí)現(xiàn)繼承,也就是說js的繼承是基于原型鏈的卷仑。原型-prototype峻村,是一個(gè)對(duì)象,用于存放共享的屬性和方法的锡凝。
原型
原型主要有這么幾個(gè)概念:
__proto__粘昨、prototype、constructor
什么是__proto__
?
js會(huì)為每個(gè)對(duì)象
添加一個(gè)屬性窜锯,這個(gè)屬性指向另外一個(gè)對(duì)象的prototype
张肾,js可以通過 Object.getPrototypeOf(obj)獲取
,chrom瀏覽器實(shí)現(xiàn)為__proto__
锚扎。
什么是prototype
?
js會(huì)為每個(gè)函數(shù)
添加一個(gè)prototype
屬性吞瞪,表示自己的原型對(duì)象。
prototype
是個(gè)對(duì)象驾孔。
什么是constructor
?
是js創(chuàng)建和初始化對(duì)象的方法芍秆,如果沒有自己指定constructor
,則會(huì)默認(rèn)有個(gè)空的constructor
翠勉。
原型對(duì)象的constructor
指向自己的創(chuàng)造者妖啥,每個(gè)原型對(duì)象都有constructor
。所有對(duì)象都會(huì)從它的原型上繼承 constructor
屬性对碌。
Tips:
1.函數(shù)也是對(duì)象,所以函數(shù)也有 __proto__ 屬性荆虱。
2.規(guī)定 Object.prototype.__proto__ === null。
3.默認(rèn)情況下朽们,除 Object 函數(shù)的 prototype.__proto__ 都是 Object.prototype克伊。
4.除Object函數(shù)的__proto__永遠(yuǎn)指向prototype。
??注意:這里有個(gè)特殊的函數(shù): Function华坦,任何函數(shù)都是 Function 的實(shí)例,包括 Object不从。所以 Function 可以說是根構(gòu)造函數(shù)惜姐。
所以 Object.__proto__ 就是Function.prototype
所以 Function.__proto__ 也是Function.prototype
以上就是主要知識(shí)點(diǎn),為了理解咱們舉個(gè)??:
創(chuàng)建一個(gè)普普通通的函數(shù)A
function A(){}
此時(shí) A 里面有prototype
,__proto__
兩個(gè)屬性。
A同時(shí)繼承了A.prototype.constructor
A.prototype
A.prototype 就是它的原型對(duì)象歹袁,里面有什么坷衍?
有constructor
和__proto__
,為什么會(huì)有__proto__
?因?yàn)閜rototype也是個(gè)對(duì)象条舔。
A.prototype.constructor 指向了誰枫耳?當(dāng)然是A,prototype里面的constructor指向它的函數(shù)
孟抗。
A.prototype.__proto__ 指向了誰迁杨?當(dāng)然是Object.prototype,因?yàn)?code>默認(rèn)情況下凄硼,任何函數(shù)的原型屬性 __proto__ 都是Object.prototype铅协。
A.__proto__
A.__proto__是什么?應(yīng)該知道它指向一個(gè)prototype摊沉,那么是誰的prototype狐史?
當(dāng)然是Function的。因?yàn)樗彩怯蒄unction創(chuàng)建的说墨。__proto__是由瀏覽器實(shí)現(xiàn)的骏全,不是標(biāo)準(zhǔn)寫法,Object 提供了獲取原型的方法:getPrototypeOf
Object.getPrototypeOf(A)
A.constructor
A.constructor尼斧,實(shí)際是 A.prototype.constructor姜贡,指向自己的創(chuàng)造者:Function
原型鏈
創(chuàng)建一個(gè)A的實(shí)例:
a = new A();
根據(jù)上面講述,a會(huì)有 __proto__
和constructor
兩個(gè)屬性,并且a.__proto__ === A.prototype:
a.constructor為a.__proto__.constructor突颊。
如果這個(gè)時(shí)候A.prototype中如果有屬性鲁豪,或者方法,a都是可以調(diào)用的律秃。
兩個(gè)對(duì)象通過__proto__連接爬橡,就組成了原型鏈。
可以給對(duì)象指定原型(不建議這么做)棒动,這里舉例僅是為了理解原型鏈糙申。將A的實(shí)例賦值給B的原型,這樣可以理解為B繼承了A船惨,B創(chuàng)建的實(shí)例b也可以調(diào)用A原型中的方法了:
整體結(jié)構(gòu)圖如下:
從上面例子可以看出js創(chuàng)建一個(gè)對(duì)象(使用new操作符)大致過程:
- 創(chuàng)建一個(gè)對(duì)象
- 給它一個(gè)原型
- 把對(duì)象放進(jìn)constructor加工
創(chuàng)建一個(gè)對(duì)象:
<!-- new 一個(gè) A 對(duì)象 -->
function newA(...args) {
var self = Object.create(A.prototype)
var res = A.prototype.constructor.call(self, ...args)
if (typeof res === 'object' && res !== null) {
return res
}
return self
}
應(yīng)用與總結(jié)
像Array中的forEach柜裸,find,filter等都是在Array.prototype上粱锐,這樣的內(nèi)置對(duì)象還有很多疙挺。
es6實(shí)現(xiàn)了class語法糖,實(shí)際還是應(yīng)用原型鏈怜浅。
// function A(name) {
// this.name = name;
// }
// A.prototype.run = function() {
// console.log(`${this.name} running...`);
// };
class A {
constructor(name) {
this.name = name;
}
run() {
console.log(`${this.name} running...`);
}
}
但是不建議修改內(nèi)置對(duì)象的原型铐然,會(huì)產(chǎn)生一些副作用蔬崩,比如: