前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript实现继承

JavaScript实现继承

作者头像
疯狂的技术宅
发布2019-03-28 10:14:17
5100
发布2019-03-28 10:14:17
举报
文章被收录于专栏:京程一灯

众所周知,JavaScript 这门语言在 ES6 出来之前是没有类(class)这一概念的,所以 JavaScript 中的类都是通过原型链来实现的。同样,使用 JavaScript 也能实现面向对象的实现继承。以下是《高程》(第三版)的读书笔记。

原型链

通过原型链实现继承很容易理解,也很简单。将子类的原型指向父类的实例即可。写个简单的例子:

代码语言:javascript
复制
// 父类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()); // "super"

对于子类来讲,其原型的指向应该是这样的:SubType -> new SuperType() -> SuperType.prototype -> Object.prototype -> null

注意:

  • 如果想要给子类添加原型上的方法,需要在子类继承了父类后添加,否则会被父类实例所覆盖。
  • 也不要用对象字面量的方式给子类原型添加新方法,这会使得之前的继承失效。

原型链的问题:

  • 父类的实例属性成为了子类的原型属性,即子类的实例共享了该父类实例的属性,如果该属性是引用类型,则子类的实例对该属性的修改会反映在所有的子类实例上。
  • 在创建子类实例时,不能向父类的构造函数传递参数。实际上,应该说是没有办法在不影响所有对象实例的情况下,给父类的构造函数传递参数。

借用构造函数

这个方法是为了解决原型链方式带来的问题,使用十分巧妙,利用了 call 方法。代码实现:

代码语言:javascript
复制
// 父类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 方法给父类传递参数。

借用构造函数的问题:

  • 方法都需要在构造函数(父类或子类)中定义,无法达到函数复用的功能。

组合继承

组合继承有时也叫伪经典继承,该继承模式将原型链和借用构造函数的技术结合在一起实现。示例代码:

代码语言:javascript
复制
// 父类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();// 指向正确的constructorSubType.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"]

从代码的例子可以观察到,组合继承模式可以让子类的多个实例既能拥有自己的属性,又能使用相同的方法,融合了原型链和借用构造函数的优点。

原型式继承

原型式继承是借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。使用如下函数实现:

代码语言:javascript
复制
function object(obj) {    function F() {}    F.prototype = obj;    return new F();
}

object 函数对传入的对象实现了浅复制。所以对所有由其创建的实例都共享了 obj 对象中的引用属性。

寄生式继承

寄生式继承模式和原型式继承模式很相似,创建了一个仅用于封装继承过程的函数,在函数内部增强对象的功能:

代码语言:javascript
复制
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 函数,对对象的功能进行增强,然而这种方式也没有达到函数复用的效果,这一点和构造函数模式一样。

寄生组合式继承

通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。寄生组合模式使用寄生模式来实现对父类原型的继承,再将结果指定给子类的原型。其基本模式如下:

代码语言:javascript
复制
function inheritPrototype(subType, superType) {    // 返回父类原型副本并赋值给子类原型
    subType.prototype = object(superType.prototype);    subType.prototype.constructor = subType;
}

再来看一个例子:

代码语言:javascript
复制
// 父类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 上创建多余的属性。开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。


往期精选文章

ES6中一些超级好用的内置方法

浅谈web自适应

使用Three.js制作酷炫无比的无穷隧道特效

一个治愈JavaScript疲劳的学习计划

全栈工程师技能大全

WEB前端性能优化常见方法

一小时内搭建一个全栈Web应用框架

干货:CSS 专业技巧

四步实现React页面过渡动画效果

让你分分钟理解 JavaScript 闭包



小手一抖,资料全有。长按二维码关注京程一灯,阅读更多技术文章和业界动态。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-09-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 京程一灯 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 原型链
  • 借用构造函数
  • 组合继承
  • 原型式继承
  • 寄生式继承
  • 寄生组合式继承
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档