在阮一峰老师的ECMAScript6入门中提到修饰器(Decorator)不能用于函数,里面提到原因是因为存在函数提升,这里只有简单几句话带过,如果熟悉JS的函数提升,就会好理解一些。
首先看看什么是函数提升。
简单的讲,函数提升指的是JavaScript编译器(解释器)将会把代码中所有的函数定义“提升”到代码的顶部,因此,可以“先”调用函数,“再”声明函数,而不是像传统的C++等语言,函数的使用必须在声明之后,通常会需要把函数声明都写在头文件中。而对于普通的变量,也是如此,var完全可以在后面的代码里面再补上
如果我们直接运行下面这一句:
console.log(foo); // ReferenceError
运行后将会抛出异常,ReferenceError: foo is not defined
但如果在后面补上变量的定义,则会正常运行,并输出undefined
console.log(foo); // outputs: undefined var foo;
其实解释器对其进行预处理,找出所有变量定义,并放在了前面,相当于如下效果:
var foo; console.log(foo);
对于函数,也是可以正常运行
foo(); // Outputs: bar function foo() { console.log('bar'); }
不过需要注意的是,函数表达式不适用
foo(); // Outputs: bar var foo = function () { console.log('bar'); }
因为这其实是一种“赋值”,将一个匿名函数赋值给变量foo(类似函数指针),而不是变量或函数声明。
下面再来说为什么修饰器不能用于函数。
原文的例子如下:
var counter = 0; var add = function () { counter++; }; @add function foo() { }
这看起来将会是先执行counter=0, 然后执行add函数,counter=1
但是其中包含三个变量定义,分别是counter,add和foo,都提升到前面后变成:
@add function foo() { } var counter; var add; counter = 0; add = function () { counter++; };
可以看到,counter=0变成在最后执行,于是counter最终为0。
因为别忘了,修饰器是在代码编译时发生的,而不是在运行时,因此add函数其实在前面就执行了。
而类不存在这样的问题,因为class定义不会提升
var foo = new Foo(); // Uncaught ReferenceError: Foo is not defined class Foo { constructor () { console.log('bar') } }
转载请保留链接:https://ilovetile.sijie.wang/3526/ 感谢您对版权的尊重