原型鏈的設(shè)計(jì)是js的精髓所在嵌赠,比較抽象。需要從內(nèi)部設(shè)計(jì)原理去理解這種設(shè)計(jì)思想,在紙上畫畫其中的關(guān)系會(huì)幫助理解问慎。
prototype對(duì)象
prototype對(duì)象的引入:所有實(shí)例對(duì)象需要共享的屬性和方法型雳,都放在這個(gè)對(duì)象中当凡,那些不需要共享的屬性和方法,就放在構(gòu)造函數(shù)中纠俭。以此來(lái)模擬類沿量。
function Animal(name) {
this.name = name
}
Animal.prototype.getName = function() {
console.log(this.name)
}
var animal1 = new Animal('Kate')
var animal2 = new Animal('Lucy')
//對(duì)象animal1 和 animal2共享方法getName
animal1.getName()
animal2.getName()
原型鏈
在javascript中,每個(gè)對(duì)象都有一個(gè)指向它的原型(prototype)對(duì)象的內(nèi)部鏈接冤荆。每個(gè)原型對(duì)象又有自己的原型朴则,直到某個(gè)對(duì)象的原型為null為止,組成這條鏈的最后一環(huán)钓简。
*proto寫入es6標(biāo)準(zhǔn)
當(dāng)一個(gè)對(duì)象被創(chuàng)建時(shí)乌妒,它的__protp__
屬性和內(nèi)部屬性[[prototype]]
指向相同的對(duì)象(也就是它的構(gòu)造函數(shù)的prototype
屬性)汹想。改變__proto__
屬性的值同時(shí)也會(huì)改變內(nèi)部屬性[[prototype]]
的值,除非該對(duì)象是不可擴(kuò)展的撤蚊。
在ES5中,所有構(gòu)造函數(shù)的__proto__
都指向Function.prototype
在ES6中侦啸,構(gòu)造函數(shù)的__proto__
指向它的父類構(gòu)造函數(shù)
obj.__proto__ === obj.[[prototype]]
// ES5
Cat.__proto__ === Function.prototype
// ES6
Cat.__proto__ === Animal
構(gòu)造函數(shù)繼承
有四種方式可以實(shí)現(xiàn)構(gòu)造函數(shù)的繼承
1.調(diào)用apply方法
function Animal() {
this.species = '動(dòng)物'
}
Animal.prototype.getName = function() {
console.log('我是動(dòng)物')
}
function Cat() {
Animal.apply(this, arguments)
}
var cat = new Cat()
cat.species // 動(dòng)物
cat.getName() // undefined
這種方法可以繼承父類構(gòu)造函數(shù)的屬性,但是無(wú)法繼承prototype
屬性挂绰,即父類中共享的方法和屬性
2.改寫prototype
對(duì)象
Cat.prototype = new Animal()
Cat.prototype.constructor = Cat
這是最常用的方法來(lái)模擬單繼承葵蒂,缺點(diǎn)是始終要保留Animal的對(duì)象践付,如果Animal對(duì)象比較大時(shí)永高,會(huì)消耗部分內(nèi)存(其實(shí)很少),并且沒有實(shí)現(xiàn)多繼承
3.直接繼承prototype
Cat.prototype = Animal.prototype
Cat.prototype.constructor = Cat
缺點(diǎn)是當(dāng)修改了Cat.prototype上的方法時(shí)會(huì)影響Animal.prototype
4.利用空對(duì)象作中介
var F = function(){}
F.prototype = Animal.prototype
Cat.prototype = new F()
Cat.prototype.constructor = Cat
缺點(diǎn)是無(wú)法繼承父類封裝的屬性
若要實(shí)現(xiàn)封裝屬性和共享同時(shí)繼承到子類中,就需要同時(shí)結(jié)合上面的1和4艇抠,請(qǐng)使用jqury的extend方法或者其他深拷貝方法。
ES6語(yǔ)法糖 —— class
ES6提供了簡(jiǎn)單的定義類的語(yǔ)法糖class
// ES6
class Cat {
constructor(name){
this.name = name
}
getName() {
console.log(this.name)
}
}
// 等價(jià)于 ES5
function Cat(name) {
this.name = name
}
Cat.prototype.getName = function() {
console.log(this.name)
}
繼承
關(guān)于繼承, ES5和ES6的區(qū)別
ES5:先構(gòu)造子類的實(shí)例對(duì)象this疚沐,然后再將父類的方法添加到this上面
ES6:先創(chuàng)造父類的實(shí)例對(duì)象this(所以必須先調(diào)用super方法),然后再用子類的構(gòu)造函數(shù)修改this
// ES6
class Cat extends Animal {
constructor() {
super(this)
}
...
}
// ES5
function Cat() {
...
}
Cat.prototype = new Animal()
Cat.prototype.constructor = Cat
手繪原型鏈圖
ES6的區(qū)別是子類構(gòu)造函數(shù)的proto指向父類構(gòu)造函數(shù)动遭。