原文地址:JavaScript实现继承javascript
众所周知,JavaScript
这门语言在 ES6
出来以前是没有类(class)这一律念的,因此 JavaScript
中的类都是经过原型链来实现的。一样,使用 JavaScript
也能实现面向对象的实现继承。如下是《高程》(第三版)的读书笔记。java
经过原型链实现继承很容易理解,也很简单。将子类的原型指向父类的实例便可。写个简单的例子:git
// 父类 function SuperType() { this.property = "super"; } // 在父类的原型上定义方法 SuperType.prototype.getSuperVal = function () { console.log(this.property); }; // 子类 function SubType() { this.property = "sub"; } // 子类继承父类 SubType.prototype = new SuperType(); var instance = new SubType(); console.log(instance.getSuperVal()); // "sub"
对于子类来说,其原型的指向应该是这样的:SubType -> new SuperType() -> SuperType.prototype -> Object.prototype -> null
。github
注意:函数
原型链的问题:this
这个方法是为了解决原型链方式带来的问题,使用十分巧妙,利用了 call
方法。代码实现:prototype
// 父类 function SuperType() { this.users = ["Jack", "Tom"]; } // 子类 function SubType() { // 继承 SuperType.call(this); } var instance1 = new SubType(); var instance2 = new SubType(); instance1.users.pop(); // "Tom" console.log(instance2.users); // ["Jack", "Tom"]
经过借用构造函数解决了共享原型属性致使的问题。同时也能够经过 call
方法给父类传递参数。设计
借用构造函数的问题:code
组合继承有时也叫伪经典继承,该继承模式将原型链和借用构造函数的技术结合在一块儿实现。示例代码:对象
// 父类 function SuperType(company) { this.company = company; this.staffs = ["Jack", "Tom"]; } // 父类方法 SuperType.prototype.getCompany = function () { console.log(this.company); }; // 子类 function SubType(company, product) { // 继承属性 SuperType.call(this, company); this.product = product; } // 继承方法 SubType.prototype = new SuperType(); // 指向正确的constructor SubType.prototype.constructor = SubType; SubType.prototype.getProduct = function () { console.log(this.product); }; // SubType实例 var instance1 = new SubType("A", "tellphone"); instance1.getCompany(); // "A" instance1.getProduct(); // "tellphone" instance1.staffs.push("Amy"); // ["Jack", "Tom", "Amy"] var instance2 = new SubType("B", "toy"); instance2.getCompany(); // "B" instance2.getProduct(); // "toy" console.log(instance2.staffs); // ["Jack", "Tom"]
从代码的例子能够观察到,组合继承模式可让子类的多个实例既能拥有本身的属性,又能使用相同的方法,融合了原型链和借用构造函数的优势。
原型式继承是借助原型能够基于已有的对象建立新对象,同时还没必要所以建立自定义类型。使用以下函数实现:
function object(obj) { function F() {} F.prototype = obj; return new F(); }
object
函数对传入的对象实现了浅复制。因此对全部由其建立的实例都共享了 obj
对象中的引用属性。
寄生式继承模式和原型式继承模式很类似,建立了一个仅用于封装继承过程的函数,在函数内部加强对象的功能:
function createAnother(obj) { var clone = object(obj); clone.saySomething = function () { alert("Hello world!"); }; return clone; } function object(obj) { function F() {} F.prototype = obj; return new F(); }
经过 createAnother
函数,对对象的功能进行加强,然而这种方式也没有达到函数复用的效果,这一点和构造函数模式同样。
经过借用构造函数来继承属性,经过原型链的混成形式来继承方法。寄生组合模式使用寄生模式来实现对父类原型的继承,再将结果指定给子类的原型。其基本模式以下:
function inheritPrototype(subType, superType) { // 返回父类原型副本并赋值给子类原型 subType.prototype = object(superType.prototype); subType.prototype.constructor = subType; }
再来看一个例子:
// 父类 function SuperType(name) { this.name = name; } // 在父类的原型上定义方法 SuperType.prototype.getName = function () { console.log(this.name); }; // 子类 function SubType(name, age) { SuperType.call(this, name); this.age = age; } // 寄生组合继承 inheritPrototype(SubType, SuperType); // 添加子类方法 SubType.prototype.getAge = function () { console.log(this.age); };
和组合继承模式相比,寄生组合式继承模式只调用了一次 SuperType
构造函数,也避免了在 SubType.prototype
上建立多余的属性。开发人员广泛认为寄生组合式继承是引用类型最理想的继承范式。
《JavaScript高级程序设计》(第三版)