6.3.1 原型链
整体思想就是子类的原型对象重写为父类的实例
function Person() {
this.name = 'zz';
this.age = 18;
} //父类的实例属性
Person.prototype.sayName = function() {
console.log(this.name);
} //父类的原型属性
function Girl() {
this.sex = 'girl';
} //子类的实例属性
Girl.prototype = new Person(); //子类的原型重写为父类的实例
Girl.prototype.sayHi = function() {
console.log('Hi');
} //子类添加原型属性
let zz = new Girl();
zz.sayName();
console.log(zz.age);
问题1.与原型模式构建对象类似,会遇到引用类型属性的问题(eg.数组),父类构造函数中的引用类型属性在子类重写原型对象之后会成为子类的原型属性,实例之间会相互影响
function Person() {
this.friends = ['zz','zxx','xxx'];
} //父类的实例属性
Person.prototype.sayHello = function() {
console.log('Hello');
} //父类的原型属性
function Girl() {
this.sex = 'girl';
} //子类的实例属性
Girl.prototype = new Person(); //子类的原型重写为父类的实例
Girl.prototype.sayHi = function() {
console.log('Hi');
} //子类添加原型属性
let zz = new Girl();
let xx = new Girl();
zz.friends.push('bbb');
console.log(xx.friends); //[ 'zz', 'zxx', 'xxx', 'bbb' ]
问题2.创建子类的实例时,无法在不影响其他实例的情况下,给父类的构造函数传值(这里我的理解是在重写时传参,不知道对不对)
6.3.2 借用构造函数
整体思想就是在子类构造函数中调用父类的构造函数
function Person(name) {
this.name = name;
this.friends = ['zxx','xxx'];
}
function Girl(name,age) {
Person.call(this,name); //传参
this.age = age;
}
let zz = new Girl('zz',18);
let xx = new Girl('xx',20);
zz.friends.push('aaa');
console.log(zz.friends); //[ 'zxx', 'xxx', 'aaa' ]
console.log(xx.friends); //[ 'zxx', 'xxx' ]
console.log(zz.name); //zz
console.log(xx.age); //20
可以传参,同时解决了引用类型属性的问题
但是也有不足之处,即父类的方法也需要定义在构造函数中(不再重写子类原型),这样就会出现构造函数创建对象时方法函数不复用的情况(函数也是对象)
6.3.3 组合继承
前两项组合
function Person(name) {
this.name = name;
this.friends = ['zxx','xxx'];
}
Person.prototype.sayName = function() {
console.log(this.name);
}
function Girl(name,age) {
Person.call(this,name); //传参
this.age = age;
}
Girl.prototype = new Person();
Girl.prototype.constructor = Girl;
Girl.prototype.sayAge = function() {
console.log(this.age);
}
let zz = new Girl('zz',18);
let xx = new Girl('xx',20);
zz.friends.push('aaa');
console.log(zz.friends); //[ 'zxx', 'xxx', 'aaa' ]
console.log(xx.friends); //[ 'zxx', 'xxx' ]
console.log(zz.name); //zz
console.log(xx.age); //20
zz.sayAge(); //18
xx.sayName(); //xx
此处的实例属性相当于是覆盖了原型中的对应属性,原型中依旧存在
6.3.4 原型式继承
不知该如何形容这个方式,书上说相当于一次浅复制,终归是返回了具有相同属性的实例
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
let person = {
name: 'zz',
friends: ['aa','bb','cc']
};
let person2 = object(person);
let person3 = object(person);
person2.friends.push('dd');
person3.name = 'zz3';
console.log(person2.name); //zz
console.log(person3.friends); //[ 'aa', 'bb', 'cc', 'dd' ]
ES5通过Object.create方法规范化了原型式继承
接收两个参数:作为基准的对象,需要添加的新的属性构成的对象
let person = {
name: 'zz',
friends: ['aa','bb','cc']
};
let person2 = Object.create(person,{
age: {
value: 18
},
job: {
value: 'teacer'
}
});
console.log(person2.name); //zz
console.log(person2.age); //18
let person3 = Object.create(person);
person3.friends.push('dd');
console.log(person2.friends); //[ 'aa', 'bb', 'cc', 'dd' ]
引用类型的属性会共享
6.3.5 寄生式继承
在函数下,浅复制一个参照对象,为复制的对象添加属性或方法,返回复制的对象
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
let person = {
name: 'zz',
friends: ['aa','bb','cc']
};
function createAnother(original) {
let clone = object(original);
clone.sayHi = function() {
console.log('Hi');
}
return clone;
}
let person2 = createAnother(person);
console.log(person2.name);
person2.sayHi();
这里添加的方法不会进行复用
6.3.6 寄生组合式继承
考虑到组合继承需要调用两次父类的构造函数,寄生组合式继承借用构造函数来继承实例属性,利用寄生式继承来复制父类原型对象,以减少一次父类构造函数的调用
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
function inheritPrototype(subType,superType) {
let prototype = object(superType.prototype);
prototype.constructor = subType;
subType.prototype = prototype;
}
function Person(name) {
this.name = name;
this.friends = ['zxx','xxx'];
}
Person.prototype.sayName = function() {
console.log(this.name);
}
function Girl(name,age) {
Person.call(this,name); //传参
this.age = age;
}
inheritPrototype(Girl,Person);
Girl.prototype.sayHi = function() {
console.log('hi')
}
let zz = new Girl('zz',18); //[ 'zxx', 'xxx' ]
console.log(zz.friends); //18
console.log(zz.age);
zz.sayName(); //zz
zz.sayHi(); //hi
继承这一块更加复杂,尤其是后三种继承方式,感觉特点不是很明显,以原型式继承和寄生式继承为主,反正我是懵懵的o(╥﹏╥)o