javascript基础学习系列一百三十三: 类混入

把不同类的行为集中到一个类是一种常见的 JavaScript 模式。虽然 ES6 没有显式支持多类继承,但通过现有特性可以轻松地模拟这种行为。
在下面的代码片段中,extends 关键字后面是一个 JavaScript 表达式。任何可以解析为一个类或一个构造函数的表达式都是有效的。这个表达式会在求值类定义时被求值:

function getParentClass() { 
 console.log('evaluated expression'); 
 return Vehicle; 
} 
class Bus extends getParentClass() {} 
// 可求值的表达式

混入模式可以通过在一个表达式中连缀多个混入元素来实现,这个表达式最终会解析为一个可以被继承的类。如果 Person 类需要组合 A、B、C,则需要某种机制实现 B 继承 A,C 继承 B,而 Person再继承 C,从而把 A、B、C 组合到这个超类中。实现这种模式有不同的策略。
一个策略是定义一组“可嵌套”的函数,每个函数分别接收一个超类作为参数,而将混入类定义为这个参数的子类,并返回这个类。这些组合函数可以连缀调用,最终组合成超类表达式:

let FooMixin = (Superclass) => class extends Superclass { 
 foo() { 
 console.log('foo'); 
 } 
}; 
let BarMixin = (Superclass) => class extends Superclass { 
 bar() { 
 console.log('bar'); 
 } 
}; 
let BazMixin = (Superclass) => class extends Superclass { 
 baz() { 
 console.log('baz'); 
 } 
}; 
class Bus extends FooMixin(BarMixin(BazMixin(Vehicle))) {} 
let b = new Bus(); 
b.foo(); // foo 
b.bar(); // bar 
b.baz(); // baz

通过写一个辅助函数,可以把嵌套调用展开:

let FooMixin = (Superclass) => class extends Superclass { 
 foo() { 
 console.log('foo'); 
 } 
}; 
let BarMixin = (Superclass) => class extends Superclass { 
 bar() { 
 console.log('bar'); 
 } 
}; 
let BazMixin = (Superclass) => class extends Superclass { 
 baz() { 
 console.log('baz'); 
 } 
}; 
function mix(BaseClass, ...Mixins) { 
 return Mixins.reduce((accumulator, current) => current(accumulator), BaseClass); 
} 
class Bus extends mix(Vehicle, FooMixin, BarMixin, BazMixin) {}
let b = new Bus(); 
b.foo(); // foo 
b.bar(); // bar 
b.baz(); // baz

小结
对象在代码执行过程中的任何时候都可以被创建和增强,具有极大的动态性,并不是严格定义的实体。下面的模式适用于创建对象。
 工厂模式就是一个简单的函数,这个函数可以创建对象,为它添加属性和方法,然后返回这个对象。这个模式在构造函数模式出现后就很少用了。
 使用构造函数模式可以自定义引用类型,可以使用 new 关键字像创建内置类型实例一样创建自定义类型的实例。不过,构造函数模式也有不足,主要是其成员无法重用,包括函数。考虑到
函数本身是松散的、弱类型的,没有理由让函数不能在多个对象实例间共享。
 原型模式解决了成员共享的问题,只要是添加到构造函数 prototype 上的属性和方法就可以共享。而组合构造函数和原型模式通过构造函数定义实例属性,通过原型定义共享的属性和方法。
JavaScript 的继承主要通过原型链来实现。原型链涉及把构造函数的原型赋值为另一个类型的实例。
这样一来,子类就可以访问父类的所有属性和方法,就像基于类的继承那样。原型链的问题是所有继承的属性和方法都会在对象实例间共享,无法做到实例私有。盗用构造函数模式通过在子类构造函数中调用父类构造函数,可以避免这个问题。这样可以让每个实例继承的属性都是私有的,但要求类型只能通过构造函数模式来定义(因为子类不能访问父类原型上的方法)。目前最流行的继承模式是组合继承,即通过原型链继承共享的属性和方法,通过盗用构造函数继承实例属性。
除上述模式之外,还有以下几种继承模式。
 原型式继承可以无须明确定义构造函数而实现继承,本质上是对给定对象执行浅复制。这种操
作的结果之后还可以再进一步增强。
 与原型式继承紧密相关的是寄生式继承,即先基于一个对象创建一个新对象,然后再增强这个新对象,最后返回新对象。这个模式也被用在组合继承中,用于避免重复调用父类构造函数导
致的浪费。
 寄生组合继承被认为是实现基于类型继承的最有效方式。
ECMAScript 6 新增的类很大程度上是基于既有原型机制的语法糖。类的语法让开发者可以优雅地定
义向后兼容的类,既可以继承内置类型,也可以继承自定义类型。类有效地跨越了对象实例、对象原型和对象类之间的鸿沟。

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值