一、构造继承
特点:
1.子类实例不会共享父类prototype中的属性和方法
2.创建子类实例时,可以向父类传参
3.可以实现多继承
缺点:
1.实例只是子类的实例,不是父类的实例
2.只能继承父类的实例属性和方法,不能继承父类的prototype中的属性和方法
3.产生冗余,每个子类都有父类实例函数的副本,影响性能
function Parent(username) {
this.username = username;
this.hello = function() {
console.log(this.username);
}
}
function Child(username, age) {
//方法1
this.method = Parent; //1.创建临时变量指向Parent所指向的对象
this.method(username); //2.通过this.method执行Parent所指向的对象函数
delete this.method; //3.销毁this.method属性,此时Child拥有了Parent所有属性和方法
//方法2
Parent.call(this,username); //1.使用call传递参数并执行Parent
//方法3
Parent.apply(this,new Array(username)); //2.使用apply传递参数数组并执行Parent
this.age = age;
this.getAge = function() {
console.log(this.age);
}
}
var parent = new Parent("Jason");
var child = new Child("Tom",18);
parent.hello();
child.hello();
child.getAge();
二、原型链继承
特点:
1.实例是子类的实例,也是父类的实例
2.父类的prototype新增属性和方法,子类都能访问到
3.简单,易于实现
缺点:
1.要为子类的prototype添加属性和方法,必须放在new Animal()语句之后执行,否则会被父类的prototype中的属性和方法覆盖
2.无法实现多继承
3.父类的prototype中的所有属性和方法被所有子类的实例共享
4.创建子类实例时,无法向父类构造函数传参
//将父类的prototype中的属性和方法追加到子类的prototype
function Parent() {}
Parent.prototype.hello = "hello";
Parent.prototype.sayHello = function() {console.log(this.hello);};
function Child() {}
Child.prototype = new Parent(); //关键
Child.prototype.constructor = Child; //将子类的prototype的constructor指回自己
Child.prototype.world = "world";
Child.prototype.sayWorld = function() {console.log(this.world);}
var child = new Child();
child.sayHello(); //继承
child.sayWorld();
三、实例继承
特点:
1.不限制调用方法,不管是new Child()还是Child(),返回的对象都是相同的效果
缺点:
1.实例时父类实例,不是子类的实例
2.不支持多继承
function Parent(hello) {
this.hello = hello;
this.sayGoodbye = function() {
console.log('goodbye');
}
}
function Child(name) {
var instance = new Parent();
instance.name = name || 'Tom';
return instance;
}
var child = new Child('Jason');
console.log(child.name);
child.sayGoodbye();
四、组合继承(推荐)
核心:调用父类构造,继承父类的属性和方法,将父类实例作为子类原型,继承父类prototype对象的属性和方法;
特点:
1.可以继承父类实例属性和方法,也可以继承父类原型属性和方法
2.既是子类的实例,也是父类的实例
3.不存在引用属性共享问题
4.可传参
5.函数可复用
缺点:调用两次父类构造函数,生成了两份实例
//混合call、原型链方式
function Parent(hello) {
this.hello = hello;
this.sayGoodbye = function() {
console.log('goodbye');
}
}
Parent.prototype.hello = "hello";
Parent.prototype.sayHello = function() {console.log(this.hello);};
function Child(hello, world) {
Parent.call(this,hello); //将Parent中的属性和方法追加到Child中
this.world = world;
}
Child.prototype = new Parent(); //将Parent的prototype包含的属性和方法追加到Child.prototype
Child.prototype.constructor = Child; //将子类的prototype的constructor指回自己
Child.prototype.sayWorld = function() {console.log(this.world);}
var child = new Child('Jason','bro');
child.sayHello(); //继承
child.sayWorld();
child.sayGoodbye(); //继承
五、拷贝继承
特点:
1.支持多继承
缺点:
1.效率低,内存占用高
2.无法获取父类不可枚举的方法
function Parent(name) {
this.name= name;
this.sayGoodbye = function() {
console.log('goodbye');
}
}
function Child(name) {
var parent= new Parent();
for(var p in parent) {
Child.prototype[p] = parent[p];
}
this.name = name || 'Tom';
}
var child = new Child();
console.log(child.name);
child.sayGoodbye();
六、寄生组合继承
核心:调用两次父类的构造时,不会初始化两次实例属性和方法,避免组合继承的缺点
特点:1.完美
缺点:1.实现较为复杂
function Parent(name) {
this.name= name;
this.sayGoodbye = function() {
console.log('goodbye');
}
}
function Child(name) {
Parent.call(this);
this.name = name || 'Tom';
}
(function(){
var Super = function(){};
Super.prototype = Parent.prototype;
Child.prototype = new Super();
})();
var child = new Child();
console.log(child.name);
child.sayGoodbye();
参考
Js如何实现继承: https://blog.csdn.net/it_sharp/article/details/87360386
Javascript 面向对象编程(一):封装 http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html
Javascript面向对象编程(二):构造函数的继承: http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html
Javascript面向对象编程(三):非构造函数的继承: http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance_continued.html
Js如何实现继承(js实现继承的五种方式):https://blog.csdn.net/it_sharp/article/details/87360386
JS实现继承的几种方式: https://www.cnblogs.com/humin/p/4556820.html
注:我写的内容是参考各位大牛写的文章,然后结合自己的理解而整理记录下来的。文章中的代码也是跑过无误后才贴上去的。如有不对之处,欢迎大家评论更正,谢谢!另外,对于上面参考文章的作者,如涉及侵权的请评论联系我做处理,感谢!