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

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

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

阅读更多

JavaScript 对象 & 原型

前言 这次的 why what or how 主题:JavaScript 对象 & 原型。 此类文章在百度上一搜一大把,其实不用再写了,但是本着把这个问题解释的清清楚楚明明白白,还是开始写了。 原因如下: 1. 面试宝典类文章,弄张图片一糊弄,让人觉得自己理解了。 2. 解释类文章,告诉你一堆语法,对语法一顿解释,告诉你就是这样的,还是没说清楚。 3. 很少有文章单独解释这个点!但这个点是基础!真的很重要! 所以本篇文章想说一说对象 & 原型,但为了确保能顺利理解,请先看完 JS 变量存储?栈 & 堆?NONONO!,因为该篇文章从变量存储的角度来解释 JavaScript 对象 & 原型,请确保看完,在看这篇文章。 什么是对象? 既然要说清楚,

By Breeze

浏览器下的 Event Loop

前言 javascript 是以单线程的形式运行在宿主环境下,javascript 采用了回调的形式来解决异步任务。 为什么是单线程? javascript 的最开始的出现是为了给 web 页面增添一些动态的效果,那么就避免不了获取页面上的元素信息,如果 javascript 是以多线程的形式运行在浏览器内,如果两个线程内的 javascript 同时去获取/修改,某个页面上的元素,那么浏览器该让哪个 javascript 线程拥有获取/修改该元素的权限呢?由于元素的信息会经常性的发生变化,那么又改如何去同步各个线程内所保存的元素信息呢? 所以综合以上问题, javascript 是单线程的原因就显示意见了,单线程在执行时,对于元素信息的引用在同一时间仅可能只有一个,那么以上所有的问题都不存在了。 什么是异步任务? 任何代码在执行时,都会碰到一些需要经过大量时间运算或是等待的代码,在浏览器的环境下,常见的就是 http 任务,比如:资源的加载(图片的 onload 事件),ajax 的请求(XMLHttpRequest 的 onLoad 事件)还有页面元素的点击事件以及

By Breeze

node 下的 Event Loop

前言 通过 浏览器下的 Event Loop ,可以得知 javascript 是一门事件驱动的语言, javascript 主线程通过不断的调用事件队列中的事件来完成异步任务。那么 Node 下是否也是如此? Node 下的事件队列 在 Node 官网有这样一篇文章:The Node.js Event Loop, Timers, and process.nextTick() 。 该文章主要讲述了 Node 中是如何处理以及实现 Node 下的 Event Loop。 主要包含以下内容: 事件队列 不同于浏览器,Node 下的有 6 个事件处理阶段,其执行顺序和队列名称如下: ┌───────────────────────────┐ ┌─>│ timers │ │ └─────────────┬─────────────┘ │ ┌─────────────┴─────────────┐ │ │ pending callbacks │ │ └─────────────┬─────────────┘ │

By Breeze

什么是 HTML 5?

前言 作为程序员,技术的落实与巩固是必要的,因此想到写个系列,名为 why what or how 每篇文章试图解释清楚一个问题。 这次的 why what or how 主题:现在几乎所有人都知道了 HTML5 ,那么 H5 到底相比于 HTML4 有什么区别呢? 升级版?标准版! HTML5 做为 HTML 标准的第 5 版,于 2014 年发布,相信关注过 HTML5 的发展史的朋友都知道该版本是 WHATWG 和 W3C 握手言和后诞生的,是 W3C 组织与浏览器厂商相互妥协的结果,其中的绝大部分规范都由 WHATWG 组织所制定,之后由 W3C 采纳并入标准中。

By Breeze