4

微信小程序decorator

 3 years ago
source link: http://blog.ilibrary.me/2021/01/03/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8Fdecorator
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
欢迎转载,请支持原创,保留原文链接:blog.ilibrary.me

decorator介绍

现在的decorator是通过babel插件babel-plugin-transform-decorators支持的.

ES5 的 Object.defineProperty 方法 。

ES7 中的 decorator 同样借鉴了python,不过依赖于 ES5 的 Object.defineProperty 方法 。

该方法允许精确添加或修改对象的属性。通过赋值来添加的普通属性会创建在属性枚举期间显示的属性(for…in 或 Object.keys 方法), 这些值可以被改变,也可以被删除。这种方法允许这些额外的细节从默认值改变。默认情况下,使用 Object.defineProperty() 添加的属性值是不可变的。

Object.defineProperty(obj, prop, descriptor)
  1. obj:要在其上定义属性的对象。
  2. prop:要定义或修改的属性的名称。
  3. descriptor:将被定义或修改的属性描述符。
  4. 返回值:被传递给函数的对象。

在ES6中,由于 Symbol类型 的特殊性,用 Symbol类型 的值来做对象的key与常规的定义或修改不同,而Object.defineProperty 是定义 key为 Symbol 的属性的方法之一。

函数decorator

下面来个例子简单介绍一下函数装饰器:

class Person { 
    @readonly 
    name() { 
        return `${this.first} ${this.last}` 
    } 
}

下面是decorator的定义。

function readonly(target, name, descriptor){ 
    // descriptor对象原来的值如下 
    // { 
    // value: specifiedFunction, 
    // enumerable: false, 
    // configurable: true, 
    // writable: true 
    // }; 
    descriptor.writable = false; 
    return descriptor; 
} 
readonly(Person.prototype, 'name', descriptor); // 类似于 Object.defineProperty(Person.prototype, 'name', descriptor);

** 关于函数decorator参数定义: **

  1. 装饰器第一个参数是 类的原型对象,上例是 Person.prototype,装饰器的本意是要“装饰”类的实例,但是这个时候实例还没生成,所以只能去装饰原型(这不同于类的装饰,那种情况时target参数指的是类本身);
  2. 第二个参数是 所要装饰的属性名
  3. 第三个参数是 该属性的描述对象

类decorator

再来一个类装饰器:

@testable 
class MyTestableClass { 
    // ... 
    } 
function testable(target) 
{ 
    target.isTestable = true;  
} 
MyTestableClass.isTestable // true

上面代码中,@testable 就是一个装饰器。它修改了 MyTestableClass这 个类的行为,为它加上了静态属性isTestabletestable 函数的参数 targetMyTestableClass 类本身。

类装饰器传参数

function testable(isTestable) { 
    return function(target) { 
        target.isTestable = isTestable; 
    } 
} 
@testable(true) 
class MyTestableClass {} 
MyTestableClass.isTestable // true @testable(false) class MyClass {} MyClass.isTestable // false

上面代码中,装饰器 testable 可以接受参数,这就等于可以修改装饰器的行为。

注意,装饰器对类的行为的改变,是代码编译时发生的,而不是在运行时。这意味着,装饰器能在编译阶段运行代码。也就是说,装饰器本质就是编译时执行的函数。

微信小程序使用样例

下面是一个检查登录状态的decorator, 如果未登录,则跳转到登录页面.

function checkLoginStatus(target, name, descriptor) {
  let oldFunc = descriptor.value;
  descriptor.value = function (...args) {
    let userInfo = wx.getStorageSync('userInfo');
    if (!userInfo) {
      wx.navigateTo({
        url: '/pages/login/login',
      })
    } else {
      oldFunc.apply(this, args)
    }
  }
  return descriptor;
}

下面是使用样例, 注意函数声明方式。

// /pages/index/index.js
  @checkLoginStatus
  getUserInfo() {
      // ...
      // ...
  }

下面的函数声明方式是不工作的, 可以正常编译运行,但是decorator不工作。 可以看到let oldFunc = descriptor.value;这个值是空的,也就是没有正确绑定目标函数getUserInfo.

// /pages/index/index.js
  @checkLoginStatus
  getUserInfo: function() {
      // ...
      // ...
  }
  1. Segmentfault: JS 装饰器,一篇就够

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK