Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

JavaScript Decorator 概念简介

  最近已经开始在一些项目中使用了 JavaScript Decorator。然而在百度上翻了翻,关于 JavaScript Decorator 的资料简直少得可怜。于是我就厚着脸皮来扯一扯这玩意儿。但是在扯这玩意儿之前还得帮大家复习下功课,因为这个概念依赖了一些旧的知识点。
  以前翻译 ES5 的时候有一个非常纠结的章节,那就是 Property Attributes。虽然在阅读时并没什么障碍,但这东西要翻译成中文会就会变成很别扭的一坨。因为我们通常把 property 和 attribute 都翻译为「属性」,难道这里要翻译成「属性的属性」么?当时我是翻译成「属性的特性」,虽然不太好,还是勉强理解吧。
  在 JavaScript 中,对象的属性上还有一堆特性。这些特性决定了属性是否可写、可删除、可枚举以及值和访问器。当我们使用 Object.defineProperty 方法时就会用到,就需要了解它们。也许一些 IE 程序员还沉浸在远古时代,根本不知道这些东西。但我想大部分人应该经常会用到这个方法才对,因为 ES5 中若想定义一个不可枚举的属性就必须用它或它的兄弟 Object.defineProperties。而且访问器属性的标准定义方式也是使用这个方法,而不是私有的 __defineGetter__ 之类的东西。
  除了 defineProperty 方法之外就是 class 语法了。因为目前的 Decorator 只定义了 class 相关的用法,还没有单独在变量定义上的用法。所以 class 的用法也是需要了解的。其实 class 就是创建类的一个糖语法,只是有个 extends 和 super 比较坑。具体我就默认大家都懂,不做详细介绍了。
  对于 Decorator,我的理解就是在 class 语法糖解析时对其属性 defineProperty 的一个劫持。Decorator 是一个函数,它可以劫持类成员甚至类本身的定义。假如我们有个这样的类
class MyClass {
  func() { return 123; }
}
  它几乎等价于
function MyClass (){};
Object.defineProperty(MyClass.prototype, 'func', {
  value: function() { return 123; },
  configurable: true,
  writable: true
});
  也就是在类的原型对象对象上定义一个不可枚举的 func 方法。如果此时我们使用 Decorator 拦截 func 的定义呢?比如这样 function Dec(base, name, descriptor) {
  console.log(base, name, descriptor);
}

class MyClass {
  @Dec
  func() {}
}
  那么这里 log 出来的三个东西和前面等价代码中 Object.defineProperty 的三个参数完全一致。可以简单地理解为当一个类成员被 Decorator 修饰时,它的定义参数将被修饰函数劫持,在这个劫持过程中可以篡改定义的内容。
  类成员毕竟还是定义在对象上的属性,那么使用 Decorator 来修饰一个类定义时又是如何呢?比如
function Dec(base) {
  console.log(base);
}

@Dec
class MyClass {
  func() { return 123; }
}
  由于直接定义类只是添加一个局部变量而已,并不是在某个对象上添加属性。这是使用 Object.defineProperty 无法定义的。所以这时修饰函数拦截到的就不再是 Object.defineProperty 的那三个参数,而是只有一个参数,它直接就是定义后的结果。比如上面的例子中 log 出来的就是 MyClass 这个对象本身。而且修饰函数中也同样可以篡改 MyClass 的属性。
  值得注意的是,decorator 的执行时机是在定义完成前的。所以在修饰函数中访问修饰的目标名只会得到一个 undefined。
  以上就是关于 JavaScript Decorator 的简单介绍。其实只要足够了解 Object.defineProperty,要理解这玩意儿肯定是轻而易举的。也许有人还会纠结它到底能干嘛用?反正我在 React 的项目里用得挺舒服,至于干嘛用自己想去。如果连这点创造力都没有还写什么代码?
网名:
54.144.24.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^