function Parent() {
this.name = 'red';
this.eat = function () {
console.log('走这里了吗')
}
}
Parent.prototype.start = function () {
console.log(this.name)
}
function Children() {}
Children的原型对象=Parent的原型对象
缺点:
实例对象p指向Parent;
实例对象p不能调用构造函数Parent的方法和属性,只能调用Parent的原型对象的方法和属性
//仅继承了Parent原型对象上的方法和属性
Children.prototype = Parent.prototype
let p = new Children();
console.log(p.name)//undefined
console.log(p.eat)//undefined
console.log(p.start)
//ƒ () {
// console.log(this.name);
//}
console.log(p.constructor)
//ƒ Parent() {
// this.name = 'red';
// this.eat = function () {
// console.log('走这里了吗');
// };
}
Children.prototype = new Parent()
缺点:
实例对象p指向Parent
Children.prototype = new Parent()//继承了Parent的原型对象prototype的方法和属性以及constructor
let p = new Children();
console.log(p)//Children {}
console.log(p.name)//red
console.log(p.start)
//ƒ () {
// console.log(this.name);
// }
console.log(p.eat)
// ƒ () {
// console.log('走这里了吗');
// }
console.log(p.constructor)
// ƒ Parent() {
// this.name = 'red';
// this.eat = function () {
// console.log('走这里了吗');
// };
// }
Children.prototype = new Parent()
Children.prototype.constructor = Children;
Children.prototype = new Parent()//继承了Parent的原型对象prototype的方法和属性以及constructor
Children.prototype.constructor = Children;
let p = new Children();
console.log(p.constructor);
// ƒ Children() {}
缺点
- 如果父构造函数中含有引用类型的属性,当某个实例改变了该引用类型的属性,则所有实例共享该实例(基本数据类型不会)
- 创建Children实例无法传参
function Parent() {
this.name = 'red';
this.arr = [1, 2, 3];
this.eat = function () {
console.log('走这里了吗')
}
}
Parent.prototype.start = function () {
console.log(this.name)
}
function Children() {
}
Children.prototype = new Parent();
Children.prototype.constructor = Children
let p1 = new Children()
let p2 = new Children()
console.log(p1.arr)
p1.name = 'blue';
p1.arr.pop();
console.log(p1.name)//blue
console.log(p2.name)//red
console.log(p1.arr)//[2,3]
console.log(p2.arr)//[2,3]
解决缺点一(构造函数继承)
某实例改变父构造函数中引用类型属性的值,所有实例共享修改后的引用类型的属性值
function Parent() {
this.arr = [1, 2, 3];
}
Parent.prototype.start = function () {
}
function Children() {
Parent.apply(this)
//相当于执行了 this.arr = [1, 2, 3];
let p1 = new Children()
let p2 = new Children()
p1.arr.pop()
console.log(p1.arr)//[2,3]
console.log(p2.arr)//[1,2,3]
解决缺点二(构造函数继承)
生成实例时不能传参的问题
function Parent(color,name) {
this.color = color;
this.name = name;
this.arr = [1, 2, 3];
this.eat = function () {
console.log('走这里了吗')
}
}
Parent.prototype.start = function () {
// console.log(this.name,'prototype')
}
function Children() {
console.log(arguments,'arguments')
//call传参为多个数值
//apply传值为数组
// Parent.apply(this,arguments)
Parent.call(this,...arguments)
}
let p1 = new Children()
let p2 = new Children('red','zhangsan')
console.log(p2.color)//red
console.log(p2.name)//zhangsan
console.log(p1.eat===p2.eat)//false
再次出现的问题
我们每次生成实例的时候都会重新生成构造函数的属性和方法
function Children() {
//call传参为多个数值
//apply传值为数组
// Parent.apply(this,arguments)
Parent.call(this,...arguments)
}
解决重新生成实例时生成构造函数的属性和方法(组合继承:原型链继承+构造函数继承)
- 实例改变引用类型的属性,所有实例共享
- 不能传参。
- 解决了以上原型链的两个问题
- 但是又出现了新的问题,每次生成实例都会重新生成一份构造函数的属性和方法
function Parent(color,name) {
this.color = color;
this.name = name;
this.arr = [1, 2, 3];
this.eat = function () {
console.log('走这里了吗')
}
}
Parent.prototype.start = function () {
console.log(this.name,'prototype')
}
function Children() {
console.log(arguments,'arguments')
//call传参为多个数值
//apply传值为数组
// Parent.apply(this,arguments)
// Parent.call(this,...arguments)
// Parent.apply(this,Array.prototype.slice.call(arguments, 1))
Parent.apply(this,[].slice.call(arguments, 1))
}
Children.prototype = new Parent();
Children.prototype.constructor = Children
let p1 = new Children(1,'red','zhangsan')
let p2 = new Children(2,'red','zhangsan')
console.log(p1.eat())
console.log(p2.eat())
console.log(p1.start===p2.start) //true
解决了三个痛点:
- 不可传参数
- 多占内存
- 改变引用类型属性,所有实例共享
寄生组合继承(再次出现问题,构造函数调用两次)
1. Parent.call(this,...arguments)
...
2.Children.prototype = new Parent();