核心: 将父类的实例做为子类的原型app
缺点: 父类新增原型方法/原型属性,子类都能访问到,父类一变其它的都变了函数
function Person (name) { this.name = name; }; Person.prototype.getName = function () { //对原型进行扩展 return this.name; }; function Parent (age) { this.age = age; }; Parent.prototype = new Person('老明'); //这一句是关键 //经过构造器函数建立出一个新对象,把老对象的东西都拿过来。 Parent.prototype.getAge = function () { return this.age; }; // Parent.prototype.getName = function () { //能够重写从父类继承来的方法,会优先调用本身的。 // console.log(222); // }; var result = new Parent(22); console.log(result.getName()); //老明 //调用了从Person原型中继承来的方法(继承到了当前对象的原型中) console.log(result.getAge()); //22 //调用了从Parent原型中扩展来的方法
基本思想
借用构造函数的基本思想就是利用call
或者apply
把父类中经过this
指定的属性和方法复制(借用)到子类建立的实例中。
由于this
对象是在运行时基于函数的执行环境绑定的。也就是说,在全局中,this
等于window
,而当函数被做为某个对象的方法调用时,this
等于那个对象。call
、apply
方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。性能
因此,这个借用构造函数就是,new
对象的时候(new建立的时候,this
指向建立的这个实例),建立了一个新的实例对象,
而且执行Parent
里面的代码,而Parent
里面用call
调用了Person
,也就是说把this
指向改为了指向新的实例,
因此就会把Person
里面的this
相关属性和方法赋值到新的实例上,而不是赋值到Person
上面,
因此全部实例中就拥有了父类定义的这些this
的属性和方法。this
由于属性是绑定到this
上面的,因此调用的时候才赋到相应的实例中,各个实例的值就不会互相影响了。prototype
核心:使用父类的构造函数来加强子类实例,等因而复制父类的实例属性给子类(没用到原型)code
缺点: 方法都在构造函数中定义, 只能继承父类的实例属性和方法,不能继承原型属性/方法,没法实现函数复用,每一个子类都有父类实例函数的副本,影响性能对象
function Person (name) { this.name = name; this.friends = ['小李','小红']; this.getName = function () { return this.name; } }; // Person.prototype.geSex = function () { //对原型进行扩展的方法就没法复用了 // console.log("男"); // }; function Parent = (age) { Person.call(this,'老明'); //这一句是核心关键 //这样就会在新parent对象上执行Person构造函数中定义的全部对象初始化代码, // 结果parent的每一个实例都会具备本身的friends属性的副本 this.age = age; }; var result = new Parent(23); console.log(result.name); //老明 console.log(result.friends); //["小李", "小红"] console.log(result.getName()); //老明 console.log(result.age); //23 console.log(result.getSex()); //这个会报错,调用不到父原型上面扩展的方法
组合继承(全部的实例都能拥有本身的属性,而且可使用相同的方法,组合继承避免了原型链和借用构造函数的缺陷,结合了两个的优势,是最经常使用的继承方式)继承
核心:经过调用父类构造,继承父类的属性并保留传参的优势,而后再经过将父类实例做为子类原型,实现函数复用原型链
缺点:调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)get
function Person (name) { this.name = name; this.friends = ['小李','小红']; }; Person.prototype.getName = function () { return this.name; }; function Parent (age) { Person.call(this,'老明'); //这一步很关键 this.age = age; }; Parent.prototype = new Person('老明'); //这一步也很关键 var result = new Parent(24); console.log(result.name); //老明 result.friends.push("小智"); // console.log(result.friends); //['小李','小红','小智'] console.log(result.getName()); //老明 console.log(result.age); //24 var result1 = new Parent(25); //经过借用构造函数都有本身的属性,经过原型享用公共的方法 console.log(result1.name); //老明 console.log(result1.friends); //['小李','小红']
核心:经过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点
缺点:堪称完美,但实现较为复杂
function Person(name) { this.name = name; this.friends = ['小李','小红']; } Person.prototype.getName = function () { return this.name; }; function Parent(age) { Person.call(this,"老明"); this.age = age; } (function () { var Super = function () {}; // 建立一个没有实例方法的类 Super.prototype = Person.prototype; Parent.prototype = new Super(); //将实例做为子类的原型 })(); var result = new Parent(23); console.log(result.name); console.log(result.friends); console.log(result.getName()); console.log(result.age);