構(gòu)造函數(shù)问拘,原型和實(shí)例的關(guān)系
每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象prototype,原型對(duì)象中有個(gè)constructor屬性惧所,該屬性指向構(gòu)造函數(shù)本身骤坐,每個(gè)實(shí)例都有一個(gè)指向原型對(duì)象的內(nèi)部指針proto,如果原型對(duì)象是另一個(gè)實(shí)例,那原型對(duì)象中又包含一個(gè)指向其原型的指針
所有引用類型都是繼承了object
所有函數(shù)的默認(rèn)原型都是Object的實(shí)例
默認(rèn)原型中包含一個(gè)指針指向object.prototype
1下愈、原型鏈
function Animal() {
this.color=['red','blue']
}
Animal.prototype.eat=function(){
console.log('eat')
};
function Dog(){
}
Dog.prototype=new Animal();
let dog=new Dog();
console.log(dog.color);
dog.eat(); //eat
原型鏈繼承還有個(gè)毛病纽绍,就是在創(chuàng)建子類型的實(shí)例時(shí),不能向父類傳遞參數(shù)
第二個(gè)是引用類型值的原型势似,當(dāng)一個(gè)實(shí)例改變這個(gè)值的時(shí)候拌夏,在所有的實(shí)例上都有所表現(xiàn)僧著,所以會(huì)用借用構(gòu)造函數(shù)的方式繼承
通過原型鏈繼承的時(shí)候不能用對(duì)象字面量創(chuàng)建原型方法,這樣會(huì)重寫原型鏈
2障簿、借用構(gòu)造函數(shù)
利用函數(shù)是在特定環(huán)境中執(zhí)行代碼的對(duì)象盹愚,使用call或者apply可以讓父類的構(gòu)造函數(shù)在將來創(chuàng)建的新對(duì)象里執(zhí)行
super.call(this)//其實(shí)這個(gè)this指的就是當(dāng)前的對(duì)象,
//因?yàn)橛胣ew 構(gòu)造出來的實(shí)例站故,會(huì)把this指向該實(shí)例本身皆怕,所以
function Father(name) {
this.name=name
}
function Child(age) {
Father.call(this,'小黃')
this.age=age;
}
let child=new Child(19)
console.log(child);//Child {name: "小黃", age: 19}
借用構(gòu)造函數(shù)模式也存在一些問題,方法都在構(gòu)造函數(shù)中定義西篓,所以函數(shù)就沒發(fā)重用了端逼,而且在父類的原型中定義的方法,在子類中都是不可見的污淋,因?yàn)橹皇抢^承了父類的構(gòu)造函數(shù)中的方法顶滩,所以借用構(gòu)造函數(shù)不會(huì)單獨(dú)使用
3、組合繼承
這個(gè)繼承方式的思路是寸爆,講原型鏈繼承和借用構(gòu)造函數(shù)繼承組合到一起礁鲁,使用原型鏈對(duì)原型屬性和方法的繼承,通過借用構(gòu)造函數(shù)實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承
function Father(name) {
this.name=name
}
Father.prototype.sayName=function () {
console.log(this.name);
}
function Child(name,age) {
Father.call(this,name)
this.age=age;
}
Child.prototype=new Father();
Child.prototype.sayAge=function(){
console.log(this.age);
}
let child1=new Child('xiao',13);
child1.sayName();
child1.sayAge()
let child2=new Child('big',14);
child2.sayName()
child2.sayAge();
父類的構(gòu)造函數(shù)定義了一個(gè)name 屬性赁豆,父類的原型上定義 了一個(gè)sa yName()的方法仅醇,子類構(gòu)造函數(shù)在調(diào)用父類構(gòu)造函數(shù)的時(shí)候傳入了name參數(shù),然后又定義了自己的屬性age魔种,然后將父類的實(shí)例賦給了子類的原型析二,又在子類的原型上定義了sayAge()方法,這樣子類的不同實(shí)例就可以分別擁有自己的屬性和使用一樣的方法了
4节预、原型式繼承
借助原型叶摄,基于已有的對(duì)象創(chuàng)建新的對(duì)象
let person={
name:"小紅",
age:13
}
let antherPerson=Object.create(person)
antherPerson.name="小黑"
antherPerson.age=15
也可以這樣寫
let person={
name:"小紅",
age:13
}
let antherPerson=Object.create(person,{
name:'小黑'
})
在沒有必要?jiǎng)?chuàng)建構(gòu)造函數(shù)的時(shí)候,只是想讓一個(gè)對(duì)象和另一個(gè)對(duì)象保持類似的情況下這種方法就是可以了安拟,不過引用類型還是會(huì)共享蛤吓,這相當(dāng)于是對(duì)象的淺拷貝
5、寄生式繼承
function object(o) {
function F() {}
o.prototype=F;
return new F();
}
function createPerson(original){
let clone=object(original);//通過調(diào)用函數(shù)創(chuàng)建一個(gè)新的對(duì)象
clone.say=function () {
console.log('hi') //以某種方式增強(qiáng)這個(gè)對(duì)象
}
return clone;//返回這個(gè)對(duì)象
}
let person={
name:"小紅",
age:13
}
let anotherPerson=createPerson(person);
anotherPerson.say()
上面代碼中基于person 返回另一個(gè)新對(duì)象糠赦,這個(gè)對(duì)象擁有person的所有屬性和方法会傲,還有自己的say()方法
但是寄生式繼承的方式為對(duì)象添加函數(shù)也不能復(fù)用,這樣會(huì)降低效率拙泽,和構(gòu)造函數(shù)模式類似
6淌山、寄生組合式繼承
由于組合式繼承會(huì)調(diào)用兩次父類的構(gòu)造函數(shù),第一次是在創(chuàng)建子類原型的時(shí)候顾瞻,第二次是調(diào)用子類構(gòu)造函數(shù)內(nèi)部調(diào)用父類的時(shí)候,
在第一次調(diào)用父類構(gòu)造函數(shù)的時(shí)候泼疑,Child.prototype會(huì)得到一個(gè)name 屬性,它是父類的實(shí)例屬性朋其,不過現(xiàn)在在子類的原型中王浴,
在調(diào)用子類構(gòu)造函數(shù)的時(shí)候脆炎,又一次調(diào)用父類的構(gòu)造函數(shù),不過這次又在新對(duì)象上創(chuàng)建了實(shí)例屬性name氓辣,這個(gè)屬性就屏蔽了原型中的的同名屬性秒裕,為了解決這個(gè),就用寄生組合繼承
function Father(name) {
this.name=name
}
Father.prototype.sayName=function () {
console.log(this.name);
}
function Child(name,age) {
Father.call(this,name)//第二次調(diào)用父類構(gòu)造函數(shù)
this.age=age;
}
Child.prototype=new Father();//第一次調(diào)用
Child.prototype.constructor=Child
寄生組合式繼承的思想:通過借用構(gòu)造函數(shù)繼承屬性钞啸,通過原型鏈的混成形式來繼承方法几蜻,不必為了指定子類型的原型而調(diào)用構(gòu)造函數(shù),我們只需要一個(gè)父類原型的副本体斩,
function Animal(color){
this.color = color
}
function Dog(color, name){
Animal.call(this, color) // 或者 Animal.apply(this, arguments)
this.name = name
}
function temp(){}
temp.prototye = Animal.prototype //父類原型的副本
Dog.prototype = new temp()
Dog.prototype.constuctor = Dog //把原型中的constrcutor指向子類的構(gòu)造函數(shù)
var dog = new Dog('黃色','小黃')
最優(yōu)的繼承就是寄生組合式繼承