ES^ Decoretors

分享

类的修饰

许多面向对象的语言都有修饰器( Decorator )函数,用来修改类的行为。
@testable
class MyTestableClass {
    // ...
}

function testable(target) {
    target.isTestable = true
}

MyTestableClass.isTestable;         // true

testable 函数即为修饰器,为 MyTestableClass 类添加了名为 isTestable 的静态属性。

一个修饰器可以理解为包装之后跟着的类的函数。

@decorator
class A {}

// 等同于

class A {}
A = decorator(A) || A
也就是说,修饰器是一个对类进行处理的函数。修饰器函数的第一个参数,就是所要修饰的目标类。

当然只要在 @ 符号后是一个函数即可,因此为了可以生成更加灵活的修饰器,我们可以通过函数返回函数的形式来编写修饰器。

function testable(isTestable) {
    return function(target) {
        target.isTestable = isTestable;
    }
}

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

@testable(false)
class MyClass {}
MyClass.isTestable;                 // false

testable 函数最终返回一个函数,符合修饰器的形式,同时通过传入不同的参数,就可以定制在不同情况下的修饰器。

方法的修饰

修饰器不仅可以修饰类,还可以修饰类的属性。
class Person {
    @readonly
    name() {
        return `${this.first} ${this.last}`
    }
}

上述代码我们为 name 方法添加了一个修饰器 readonlyreadonly 同样也是一个函数,如下

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);

相比于类修饰器,方法修饰器多了两个参数,分别为:

  • name: 修饰器修饰的属性名。
  • descriptor: 该属性名对应属性的描述对象。

举个例子:使用 @log 修饰器,达成输出日志的目的

function log(target, name, descriptor) {
    var oldValue = descriptor.value;
    
    descriptor.value = function() {
        console.log(`Calling ${name} with`, arguments);
        return oldValue.apply(this, arguments);
    }
    
    return descriptor;
}

class Math {
    @log
    add(a, b) {
        return a + b;
    }
}

const math = new Math();

math.add(2, 4);
// Calling add with [2, 4];
// 6

这样就达成了在执行方法的时候,输出一条日志的目的,当然修饰器能做的事情可以有更多。

一些可以使用的修饰器的类库:

阅读更多

ES6 Proxy

简单谈谈 Proxy:在目标对象之前架设一层 拦截 ,当对该对象进行 访问/赋值 时,必须先通过这层拦截,从而实现对属性进行 访问/赋值 时的过滤和改写。 一个简单的例子 let obj = new Proxy({}, { get(target, key, receiver) { console.log(`getting ${key}!`); return Reflect.get(target, key, receiver); }, set(target, key, value, receiver) { console.log(`setting ${key}!`); return Reflect.set(target, key, value, receiver); } }); obj.count

By Breeze

ES6 变量解构

简单说说 假设有这样一个场景:你需要向你的服务器获取一些基本的数据(config 对象)来初始化页面。当你需要去获取其中的配置项时, ES5 是这么写的: var config = { params1: 520, params2: 1314 }; // 为了确保下方的代码不依赖于 config 对象,重新赋值为一个更有意义的名称。 var params1 = config.params1, params2 = config.params2 console.log(params1 + ' !! ' + params2) // 520 !! 1314 看着代码量也不是很大,但这只有两个配置项,万一要有几十个呢,不得一直 congif.xxx 了。不得不得这的确很烦,那有没更简单的方式呢? ES6 提出了以下方式: var config = { params1: 520, params2:

By Breeze

ES6 Array

简单谈谈 ES5 中原本就提供了数组,这里谈谈数组下都有哪些方法新增,哪些方法进行了变更。 Array.from 在 javascript 中有这样一类的存在:类数组,它不是数组,却能像数组那么操作,如下便是一个类数组结构。 let arrayLike = { "0": "a", "1": "b", "2": "c", length: 3 }; 类数组结构:可以像数组那样取值、 for 循环,但是却不能适用数组 forEach/splice 等数组特定的方法,在 ES5 中必须使用一些特殊的方法来将一个类数组结构转化成数组,而在 ES6 中,

By Breeze