js的继承方式(共6种):javascript
定义一个父级函数:
function Animal(name){ this.name = name; this.sleep = function(){ console.log(this.name+"在睡觉") } } Animal.prototype.eat = function(food){ console.log(this.name+"再吃"+food); }
第一种:原型链继承(父类实例做为子类的原型)java
function Cat(name){ this.name = name; } Cat.prototype.color = "白色"; Cat.prototype = new Animal(); var cat1 = new Cat("Tom"); // 实例1 var cat2 = new Cat("Jim"); // 实例2 var cat3 = new Cat("Sun"); // 实例3 console.log(cat1.name); console.log(cat1.color); // undefined console.log(cat2.sleep()); console.log(cat3.eat("fish")) 特色: 简单易实现 父类实例的属性和方法子类均可以继承 缺点: 想要新增原型属性和方法必须放在new Animal()语句以后 不能实现多继承(一个子类同时继承多个父类) 来自原型对象的属性是全部实例共享的 建立子类实例时,没法向父类构造函数传参
第二种:构造函数继承(经过使用call改变this指向,指向父类实例,至关于复制父类实例的属性给子类)app
function Cat(name){ Animal.call(this); this.name = name; } var cat1 = new Cat("Tom"); console.log(cat1.name); console.log(cat1.sleep()); console.log(cat1.eat("fish")) // cat1.eat is not a function 特色: 能够实现多继承 建立子类实例时能够向父类传参 缺点: 只能继承父类实例的属性和方法,不能继承原型的方法 函数不可复用 实例只是子类实例不是父类实例
第三种:实例继承(为父类实例添加新属性,做为子类实例返回)函数
function Cat(name){ console.log(this) var instance = new Animal(); instance.name = name; return instance; } var cat1 = new Cat("Tom"); var cat2 = Cat("Jim"); console.log(cat1.name) // Tom console.log(cat2.name) // Jim 特色: 不限制调用方式,new 构造函数 或者直接调用子类函数 获得的都是一样的结果 缺点: 不支持多继承 实例是父类实例,不是子类的实例
第四种:拷贝继承(获取父类实例,经过循环父类实例,把父类实例的属性和方法都赋给子类)this
function Cat(name){ var animal = new Animal(); for(var p in animal){ Cat.prototype[p] = animal[p]; } Cat.prototype.name = name; } var cat1 = new Cat("Jim"); var cat2 = new Cat("Jim"); console.log(cat1.name); console.log(cat2.eat("fish")); 特色: 能够实现多继承 缺点: 由于每次都要循环,形成内存消耗严重,效率低 不能够枚举的属性方法就会获取不到
第五种:组合继承(经过调用父类的构造函数,继承了父类的属性和方法,并保留了传参的优势,经过将父类实例做为子类的原型,实现了函数的复用)spa
function Cat(name){ Animal.call(this); this.name = name; } Cat.prototype = new Animal(); Cat.prototype.constructor = Cat; // console.log(Cat.prototype.constructor); var cat1 = new Cat("Tom"); var cat2 = new Cat("Li"); console.log(cat1.name); console.log(cat2.eat("apple")) 特色: 既能够继承实例的属性和方法,也能够继承构造函数的属性和方法 子类实例能够给父类传参 实例既是子类实例也是父类实例 函数可复用 缺点: 调用了两次父类构造函数,生成了两份实例 (1). 设置子类实例原型的时候 Cat.prototype = new Animal(); (2). 建立子类实例的时候 var cat1 = new Cat("Tom");
第六种:寄生组合继承prototype
function Cat(name){ Animal.call(this); this.name = name; } (function(){ // 建立一个没有实例方法的类 var Cate = function(){ } // 将父类原型当作这个类的原型 Cate.prototype = Animal.prototype; // 把实例做为子类的原型 Cat.prototype = new Cate(); })() var cat1 = new Cat("Tom"); var cat2 = new Cat("Jim"); console.log(cat1); console.log(cat2.eat("apple")); 特色: 既能够继承实例的属性和方法,也能够继承构造函数的属性和方法 子类实例能够给父类传参 实例既是子类实例也是父类实例 能够实现多继承 函数可复用 经过寄生的方式,去掉了父类的实例属性,调用两次父类构造函数时不会初始化两属性和方法