构造函数借助call
- call能在特定的作用域中调用函数,能改变函数的作用域,实际上是改变函数体内 this 的值 。
function parent(){
this.name = 'a';
}
function child(this){
parent.call(this) //parent 使用了.call 拿到了parent 的属性
}
let c = new child;
console.log(c);
- 但子类只能拿到父类的属性值,一旦父类原型对象存在某一个方法,子类就不能够继承,所以我们做一下改进
借助原型链继承
function parent() {
this.name = 'a';
this.num = [1,2,3,4];
}
function child() {
}
child.prototype = new parent();
let c = new child();
console.log(c.name);
console.log(c.num);
- 父类的属性和方法都能够访问,但这里很容易忽略一个bug,
function parent() {
this.name = 'a';
this.num = [1,2,3,4];
}
function child() {
}
child.prototype = new parent();
let c = new child();
// console.log(c.name);
// console.log(c.num);
let d = new child();
d.num.push(5);
console.log(c.num,d.num)
- 我们明明是把对象d的play属性加了个5,c的属性也跟着变了。原来我们c , d都是 同一个原型对象 所以我们再做改进
组合一下
function parent() {
this.name = 'a';
this.num = [1,2,3,4];
}
function child() {
parent.call(this) // 加了这一行代码
}
child.prototype = new parent();
let c = new child();
// console.log(c.name);
// console.log(c.num);
let d = new child();
d.num.push(5);
console.log(c.num,d.num)
- 这样就解决是同一个原型对象的问题了,但问题又多了一个,我们在
child.prototype = new parent()这一步又要去调用parent(),我们再进一步优化。
优化1
- 我们倒不妨直接把父类的原型对象直接复制给子类
function parent() {
this.name = 'a';
this.num = [1,2,3,4];
}
function child() {
parent.call(this)
}
child.prototype = parent.prototype; //把 new parent() 改成 parent.prototype
let c = new child();
// console.log(c.name);
// console.log(c.num);
let d = new child();
d.num.push(5);
console.log(c.num,d.num)
- 果然我们这样可以实现,不过我们好像是把父类的属性方法都继承过来了,但子类实例的构造函数是Parent4,显然这是不对的,应该是Child4。?
优化2-寄生组合继承
function parent() {
this.name = 'a';
this.num = [1,2,3,4];
}
function child() {
parent.call(this)
}
child.prototype = Object.create(parent.prototype);
child.prototype =parent.prototype
child.prototype.constructor = child;
let c = new child();
// console.log(c.name);
// console.log(c.num);
let d = new child();
d.num.push(5);
console.log(c)
总结
学习别人的文章,再拿到自己手里再去实现,自己写篇文章也能很好捋清思路,学得更透彻,也不失为一种很好的学习方法
参考文章 :juejin.cn/post/684490…