子类继承父类中的属性和方法:目的是让子类的实例能够调取父类的属性和方法
父类的实例作为子类的原型
将构造函数的原型设置为另一个构造函数的实例对象,这样就可以继承另一个原型对象的所有属性和方法,可以继续往上,最终形成原型链。 function Woman(){ } Woman.prototype= new People(); Woman.prototype.name = 'haixia'; let womanObj = new Woman();优点:
简单易于实现,父类的新增的实例与属性子类都能访问
缺点:
可以在子类中增加实例属性,如果要新增加原型属性和方法需要在new 父类构造函数的后面
无法实现多继承
创建子类实例时,不能向父类构造函数中传参数
复制父类的实例属性给子类
为了解决原型中包含引用类型值的问题,开始使用借用构造函数,也叫伪造对象或经典继承 function Woman(name){ //继承了People People.call(this); //People.call(this,'wangxiaoxia'); this.name = name || 'renbo' } let womanObj = new Woman();优点:
解决了子类构造函数向父类构造函数中传递参数
可以实现多继承(call或者apply多个父类)
缺点:
方法都在构造函数中定义,无法复用
不能继承原型属性/方法,只能继承父类的实例属性和方法
不自定义类型的情况下,临时创建一个构造函数,借助已有的对象作为临时构造函数的原型,然后在此基础实例化对象,并返回。
function object(o){ function F(){} F.prototype = o; return new F();本质上是object()对传入其中的对象执行了一次浅复制
var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = object(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob"); var yetAnotherPerson = object(person); yetAnotherPerson.name = "Linda"; yetAnotherPerson.friends.push("Barbie"); alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"原型的引用类型属性会在各实例之间共享。
当只想单纯地让一个对象与另一个对象保持类似的情况下,原型式继承是完全可以胜任的。
注意:
ES5 通过新增 Object.create()方法规范化了原型式继承。这个方法接收两个参数:一个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。在传入一个参数的情况下,Object.create()与这里的object()方法的行为相同。第二个参数与Object.defineProperties()方法的第二个参数格式相同:每个属性都是通过自己的描述符定义的。
调用父类构造函数,继承父类的属性,通过将父类实例作为子类原型,实现函数复用
function Cat(name){ Animal.call(this); this.name = name || 'Tom'; }Cat.prototype = new Animal();// 感谢 @学无止境c 的提醒,组合继承也是需要修复构造函数指向的。Cat.prototype.constructor = Cat;
// Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); // true特点:
弥补了方式2的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法 既是子类的实例,也是父类的实例 不存在引用属性共享问题 可传参 函数可复用 缺点:
调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
其实就是在原型式继承得到对象的基础上,在内部再以某种方式来增强对象,然后返回。
function createAnother(original) { var clone = object(original); clone.sayHi = function() { alert("hi"); }; return clone; }思路与寄生构造函数和工厂模式类似。
新的对象中不仅具有original的所有属性和方法,而且还有自己的sayHi()方法。
寄生式继承在主要考虑对象而不是自定义类型和构造函数的情况下非常有用。
由于寄生式继承为对象添加函数不能做到函数复用,因此效率降低。
通过寄生的方式来修复组合式继承的不足,完美的实现继承
****核心:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点
组合继承是JS中最常用的继承模式,但其实它也有不足,组合继承无论什么情况下都会调用两次超类型的构造函数,并且创建的每个实例中都要屏蔽超类型对象的所有实例属性。
寄生组合式继承就解决了上述问题,被认为是最理想的继承范式。
function Cat(name){ Animal.call(this); this.name = name || 'Tom'; } (function(){ // 创建一个没有实例方法的类 var Super = function(){}; Super.prototype = Animal.prototype; //将实例作为子类的原型 Cat.prototype = new Super(); })(); // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); //true主要利用class配合extends与super实现继承;
首先利用class构造一个父类
class Person { //构造函数实现属性定义 constructor(name,age){ this.name = name this.age =age } //原型上的方法 say(){ console.log(this.name) } }然后利用extends与super实现子类继承
class User extends Person { constructor(name,age,tel){ super(name,age); this.tel = tel; } call(){ console.log(this.tel) } }