为了账号安全,请及时绑定邮箱和手机立即绑定
慕课专栏

目录

索引目录

Vue 核心源码详解38讲

原价 ¥ 68.00

立即订阅
07 JavaScript 中的类和 Mixin
更新时间:2020-12-04 11:58:35
人生太短,要干的事太多,我要争分夺秒。——爱迪生

JavaScript 是一种弱类型的语言,且函数是一等公民,因此在代码的组织上非常灵活,有非常多的方法可以实现代码的复用。

“函数是一等公民”的意思,即函数和其他的类型一样,并没有什么特殊。因此在 JavaScript 中,函数可以和其他类型的数据一样,被当成值返回、被当成参数传递、被不同的变量赋值/引用等。

具体到代码复用方面,在 JavaScript 中被使用最广泛的就是类和 Mixin。

JavaScript 中的类

类,即 Class,在 Java 等语言中,类是最基本的概念,所有的代码都要基于类来编写。对类一个最直观的理解是“它是对象的蓝本,对象的形状由类的定义来决定”。因此,只要我们将需要复用的代码封装到类中,然后在不同的场合都使用这个类的实例,就可以在各种不同的场合来复用这些相同的代码。

如果我们希望复用一部分代码,但是又希望不同场合的对象形状是不同的,则可能需要使用类的继承:将需要复用的代码放到基类中,将不同的部分放入不同的子类中,然后不同场合视需要使用不同子类的实例,但这些实例仍然可以共享基类的方法和成员,从而实现代码复用。

class Animal{
  constructor() {
    this.head = 1;
  }
  eat() {

  }
}

class Cat extends Animal{
  constructor() {
    super();
    this.legs = 4;
  }
  makeSound() {
    console.log('miao');
  }
}

在这个例子中,我们定义了一个类Animal,它头(head)的数量为1,并且有eat()方法。接下来有一个Cat类继承自Animal类,它加上了自定义的成员legsmakeSound(),并且从基类Animal中继承了headeat(),因此它既可以使用自定义的成员,也可以利用基类的成员,这便是继承复用代码的方式。

在 ES6 之前,JavaScript 中是没有正统的“类”的概念的,这也是 JavaScript 饱受误解的一个重要来源:习惯了使用“类”来组织代码的开发者来到了 JavaScript 的世界后,发现他们熟悉的概念和模式都不见了,因此觉得这门语言本身是有非常大的缺陷甚至是“玩具语言”。

但是因为 JavaScript 在设计之初有参考一些 Java 的概念,加上它非常灵活,懂这门语言的开发者仍然可以使用一些方法来模拟类,从而将经典的基于类的概念和模式引入 JavaScript 中。这些方法中使用最广泛的就是“构造函数”加“基于原型的继承”。

上面的例子用构造函数和基于原型的继承,写起来类似这样:


function Animal(){
  this.head = 1;
}
Animal.prototype.eat = function() {
};

function Cat(){
  this.legs = 4;
}
Cat.prototype = new Animal();
Cat.prototype.makeSound = function() {
    console.log('miao');
};

ES6 正式为 JavaScript 加上了“类”的概念,但它在概念和性质上与基于原型的类模拟相差不多,在日常使用的场景下,基本上可以认为它们是相同的。

而有时候为了代码的灵活或者兼容,开发者仍然会使用 ES6 之前的类的写法,Vue 源代码中亦是如此。为了避免无谓的争论,后文中将不区分 ES6 的类和 ES5 基于原型的模拟类,而统称为“类”。

Mixin

Mixin 在一些中文文档中也被称为“混入”或者“混元”,是另一种实现代码复用的方式。在具体的原理上,类主要通过“继承”来复用代码,而 Mixin 则主要是通过“组合”。

Mixin 的具体做法是:定义一些单独的方法,然后在某一些时机(例如初始化),动态地修改当前使用的对象,将这些方法挂载到对象上去,从而实现不同对象中都可以使用同一个方法。这种行为充分地复用了 JavaScript 语言的动态性,在运行时修改对象,从而改变对象的行为,实现代码复用。

例如在 Vue 的构造函数定义中,就使用了一系列的 mixin 来扩展 Vue 类型的方法,以initMixin()为例:

export function initMixin (Vue: Class<Component>) {
  Vue.prototype._init = function (options?: Object) {
  }
}

initMixin()被调用时,就会在传入的Vue变量(Vue 构造函数)的原型上添加_init()方法。

Vue 中大量使用了类似上面示例的 Mixin,从而使得功能代码可以分散在不同的代码文件中,从而保持代码结构简单。

使用继承还是使用 Mixin

继承和 Mixin 都能很好地达到代码复用的目的,但它们也有各自的优缺点。

当继承使用过多时,容易出现一些问题,例如继承层数过多、大量覆盖父类实现等,使用不当时会导致代码难以维护。关于这一点,可以参考更多的资料,例如被广泛流传的“组合优于继承”的说法,在此不再赘述。

Mixin 也有一些缺点,例如代码组织过于灵活,很容易导致代码间的互相引用混乱,从而影响可维护性。

因此在实际使用中,选择使用继承还是使用 Mixin 来组织代码并不是一个有明确答案的问题,需要根据实际情况来进行取舍。Vue 中大量使用了 Mixin 来组织代码。

小结

了解类和 Mixin 有助于我们从宏观上去构架代码,从而使文件组织更合理,代码结构更可读。而具体到 Vue 源码上,则能帮助我们拨开 Vue 源码结构上的迷雾,使我们在阅读 Vue 源码时不被与类和 Mixin 有关的代码干扰,从而更好地理解 Vue 的代码组织形式和各个部分的实现原理。

}
立即订阅 ¥ 68.00

你正在阅读课程试读内容,订阅后解锁课程全部内容

千学不如一看,千看不如一练

手机
阅读

扫一扫 手机阅读

Vue 核心源码详解38讲
立即订阅 ¥ 68.00

举报

0/150
提交
取消