//8.继承
构造函数方式继承
构造函数方式继承的缺点:构造函数的方法会在实例化的时候多次执行,没有必要。
//8.1构造函数方式继承
function SuperType1(){
this.property = true
this.arr = [1,2,3]
this.fuc = function () {
console.log('just test')
}
}
function SubType1() {
SuperType1.call(this)
this.subproperty = false
}
var obj1 = new SubType1()
var obj2 = new SubType1()
obj1.arr.push(4)
console.log(obj1.arr)//[1, 2, 3, 4] 引用类型没有互相污染,但是fuc方法每次实例话都会新生成一次,没必要。
console.log(obj2.arr)//[1, 2, 3] 引用类型没有互相污染,但是fuc方法每次实例话都会新生成一次,没必要。
原型方式继承
原型方式继承缺点:如果父级构造函数内有引用类型,如果此时有两个实例对象,其中一个实例对象改变了引用类型的值,则另一个实例对象的引用类型值也会相应改变。这不是我们期望的。
//8.2原型方式继承 (为什么原型继承,因为构造函数方式继承的话,每次new一个实例,相同的方法都会重新生成一次,没有必要)
function SuperType2(){
this.property = true
this.arr = [1,2,3]
}
SuperType2.prototype.fuc = function(){//将构造函数继承里的fuc提出来到原型继承里
console.log('just test')
}
function SubType2(){
this.subproperty = false
}
SubType2.prototype = new SuperType2()//将SubType2的prototype设置为需要继承的构造函数的实例
var obj3 = new SubType2()
var obj4 = new SubType2()
obj3.arr.push(4)
console.log(obj3.arr)//[1, 2, 3, 4] 原型链继承方式,会让引用类型的值发生改变互相污染
console.log(obj4.arr)//[1, 2, 3, 4] 原型链继承方式,会让引用类型的值发生改变互相污染
obj4.property = false
console.log(obj3.property)//true 基本类型值不会污染
console.log(obj4.property)//false 基本类型值不会污染
组合方式继承(构造函数+原型链)
由于构造函数方式继承会导致函数内方法多次实例化(没有必要),原型链继承又有可能导致引用类型值的改变。所以现在考虑将两者相结合。
//8.3 构造函数+原型链组合方式继承(思路:把属性放在构造函数里,把方法提出到prototype里,子构造函数的protoype指向父构造函数的实例)
function SuperType3(){
this.property = true
this.arr = [1,2,3]
}
SuperType3.prototype.fuc = function(){//将构造函数继承里的fuc提出来到原型继承里
console.log('just test')
}
function SubType3(){
//继承属性
SuperType3.call(this)//等价于下方注释部分,但由于是继承,所以要这样写,因为大多数时候你并不知道父构造函数里有什么
// this.property = true
// this.arr = [1,2,3]
this.subproperty = false
}
SubType3.prototype = new SuperType3()
var obj5 = new SubType3()
var obj6 = new SubType3()
obj5.arr.push(4)
console.log(obj5.arr)//[1, 2, 3, 4] 引用类型放在构造函数内,没有对其他实例造成污染
console.log(obj6.arr)//[1, 2, 3] 引用类型放在构造函数内,没有对其他实例造成污染
组合方式优化1
上述组合方式继承还有问题,就是:
(1)SubType3.prototype = new SuperType3()时会调用SuperType3;
(2)SubType3内部执行SuperType3.call(this)时又会调用一次SuperType3。
//8.4 组合方式优化1
function SuperType4(){
this.property = true
this.arr = [1,2,3]
}
SuperType4.prototype.fuc = function(){//将构造函数继承里的fuc提出来到原型继承里
console.log('just test')
}
function SubType4(){
//继承属性
SuperType4.call(this)//等价于下放注释部分,但由于是继承,所以要这样写,因为大多数时候你并不知道父构造函数里有什么
// this.property = true
// this.arr = [1,2,3]
this.subproperty = false
}
SubType4.prototype = SuperType4.prototype
var obj7 = new SubType4()
var obj8 = new SubType4()
obj7.arr.push(4)
console.log(obj7.constructor)//ƒ SuperType4()
组合方式优化2
上述优化1依然有问题,虽然SuperType4只调用了一次,但是
...
SubType4.prototype = SuperType4.prototype
...
这里又会导致SubType4实例化对象的constructor实际是指向SuperType4的。
所以,我们将此处修改为:
...
SubType4.prototype = SuperType4.prototype
SubType4.prototype.constructor = SubType4
...
//加Object.create()前
这样SubType4的原型对象的contructor属性就指向SubType4了。但这样就够了吗?我们发现,此时SuperType4.prototype.constructor也指向了SubType4,这不是我们期望的。
所以还需要做以下这步:
...
SubType4.prototype = Object.create(SuperType4.prototype)
SubType4.prototype.constructor = SubType4
...
//加Object.create()后
对比一下前后两者区别:
//console.log(SuperType4.prototype)
{fuc: ƒ, constructor: ƒ}
fuc:ƒ ()
constructor:ƒ SuperType4() //若直接SubType4.prototype = SuperType4.prototype,SuperType4将会被替换成SubType4
__proto__:Object
//console.log(Object.create(SuperType4.prototype))
SuperType4 {}
__proto__: //通过SubType4.prototype = Object.create(SuperType4.prototype)创建一个新的对象,则会在__proto__平级处会增加一个constructor: SubType4。下方的SuperType4并不会被替换。
fuc:ƒ ()
constructor:ƒ SuperType4()
__proto__:Object
上述代码中,Object.create(SuperType4.prototype)基本等价于:
function object(o){//返回一个函数的实例,该实例的原型对象等于传入的参数
function F(){};
F.prototype = o;
return new F();
}
object(SuperType4.prototype)
也就是说,Object.create()方法会创建一个新的对象,对象的prototype即为传入的参数。
最终,我们得到了最优的继承方式:
function SuperType4(){
this.property = true
this.arr = [1,2,3]
}
SuperType4.prototype.fuc = function(){//将构造函数继承里的fuc提出来到原型继承里
console.log('just test')
}
function SubType4(){
//继承属性
SuperType4.call(this)//等价于下放注释部分,但由于是继承,所以要这样写,因为大多数时候你并不知道父构造函数里有什么
// this.property = true
// this.arr = [1,2,3]
this.subproperty = false
}
SubType4.prototype = Object.create(SuperType4.prototype)
SubType4.prototype.constructor = SubType4