1
0
mirror of https://github.com/ruanyf/es6tutorial.git synced 2025-05-24 18:32:22 +00:00

edit class/decorator

This commit is contained in:
ruanyf 2015-08-09 17:32:24 +08:00
parent 4960a1808f
commit 2ffd5f9e97
4 changed files with 82 additions and 29 deletions

View File

@ -844,6 +844,20 @@ console.log(MyTestableClass.isTestable) // true
上面代码中,`@testable`就是一个修饰器。它修改了MyTestableClass这个类的行为为它加上了静态属性isTestable。
基本上,修饰器的行为就是下面这样。
```javascript
@decorator
class A {}
// 等同于
class A {}
A = decorator(A) || A;
```
也就是说,修饰器本质上就是能在编译时执行的函数。
修饰器函数可以接受三个参数依次是目标函数、属性名和该属性的描述对象。后两个参数可省略。上面代码中testable函数的参数target就是所要修饰的对象。如果希望修饰器的行为能够根据目标对象的不同而不同就要在外面再封装一层函数。
```javascript
@ -983,6 +997,64 @@ class Person {
除了注释修饰器还能用来类型检查。所以对于Class来说这项功能相当有用。从长期来看它将是JavaScript代码静态分析的重要工具。
### 为什么修饰器不能用于函数?
修饰器只能用于类和类的方法,不能用于函数,因为存在函数提升。
```javascript
var counter = 0;
var add = function () {
counter++;
};
@add
function foo() {
}
```
上面的代码意图是执行后counter等于1但是实际上结果是couter等于0。因为函数提升使得实际执行的代码是下面这样。
```javascript
var counter;
var add;
@add
function foo() {
}
counter = 0;
add = function () {
counter++;
};
```
下面是另一个例子。
```javascript
var readOnly = require("some-decorator");
@readOnly
function foo() {
}
```
上面代码也有问题,因为实际执行是下面这样。
```javascript
var readOnly;
@readOnly
function foo() {
}
readOnly = require("some-decorator");
```
总之,由于存在函数提升,使得修饰器不能用于函数。类是不会提升的,所以就没有这方面的问题。
### core-decorators.js
[core-decorators.js](https://github.com/jayphelps/core-decorators.js)是一个第三方模块,提供了几个常见的修饰器,通过它可以更好地理解修饰器。

View File

@ -150,7 +150,6 @@ foo()
另一个需要注意的地方是,参数默认值所处的作用域,不是全局作用域,而是函数作用域。
```javascript
var x = 1;
function foo(x, y = x) {
@ -158,20 +157,17 @@ function foo(x, y = x) {
}
foo(2) // 2
```
上面代码中参数y的默认值等于x由于处在函数作用域所以x等于参数x而不是全局变量x。
上面代码中参数y的默认值等于x由于处在函数作用域所以y等于参数x而不是全局变量x。
参数变量是默认声明的所以不能用let或const再次声明。
```javascript
function foo(x = 5) {
let x = 1; // error
const x = 2; // error
}
```
上面代码中参数变量x是默认声明的在函数体中不能用let或const再次声明否则会报错。
@ -179,7 +175,6 @@ function foo(x = 5) {
参数默认值可以与解构赋值,联合起来使用。
```javascript
function foo({x, y = 5}) {
console.log(x, y);
}
@ -187,7 +182,6 @@ function foo({x, y = 5}) {
foo({}) // undefined, 5
foo({x: 1}) // 1, 5
foo({x: 1, y: 2}) // 1, 2
```
上面代码中foo函数的参数是一个对象变量x和y用于解构赋值y有默认值5。
@ -197,7 +191,6 @@ foo({x: 1, y: 2}) // 1, 2
ES6引入rest参数形式为“...变量名”用于获取函数的多余参数这样就不需要使用arguments对象了。rest参数搭配的变量是一个数组该变量将多余的参数放入数组中。
```javascript
function add(...values) {
let sum = 0;
@ -209,7 +202,6 @@ function add(...values) {
}
add(2, 5, 3) // 10
```
上面代码的add函数是一个求和函数利用rest参数可以向该函数传入任意数目的参数。

View File

@ -520,7 +520,7 @@ fproxy.foo; // 'Hello, foo'
拦截`for (var x in proxy)`,返回一个遍历器。
**6hasOwn(target, propKey)**
**6hasOwn(target, propKey)**
拦截`proxy.hasOwnProperty('foo')`,返回一个布尔值。
@ -842,7 +842,6 @@ Reflect.defineProperty(obj, name, desc);
Object.observe方法用来监听对象以及数组的变化。一旦监听对象发生变化就会触发回调函数。
```javascript
var user = {};
Object.observe(user, function(changes){
changes.forEach(function(change) {
@ -853,7 +852,6 @@ Object.observe(user, function(changes){
user.firstName = 'Michael';
user.lastName = 'Jackson';
user.fullName // 'Michael Jackson'
```
上面代码中Object.observer方法监听user对象。一旦该对象发生变化就自动生成fullName属性。
@ -861,7 +859,6 @@ user.fullName // 'Michael Jackson'
一般情况下Object.observe方法接受两个参数第一个参数是监听的对象第二个函数是一个回调函数。一旦监听对象发生变化比如新增或删除一个属性就会触发这个回调函数。很明显利用这个方法可以做很多事情比如自动更新DOM。
```javascript
var div = $("#foo");
Object.observe(user, function(changes){
@ -870,7 +867,6 @@ Object.observe(user, function(changes){
div.text(fullName);
});
});
```
上面代码中只要user对象发生变化就会自动更新DOM。如果配合jQuery的change方法就可以实现数据对象与DOM对象的双向自动绑定。
@ -878,7 +874,6 @@ Object.observe(user, function(changes){
回调函数的changes参数是一个数组代表对象发生的变化。下面是一个更完整的例子。
```javascript
var o = {};
function observer(changes){
@ -891,20 +886,17 @@ function observer(changes){
}
Object.observe(o, observer);
```
参照上面代码Object.observe方法指定的回调函数接受一个数组changes作为参数。该数组的成员与对象的变化一一对应也就是说对象发生多少个变化该数组就有多少个成员。每个成员是一个对象change它的name属性表示发生变化源对象的属性名oldValue属性表示发生变化前的值object属性指向变动后的源对象type属性表示变化的种类。基本上change对象是下面的样子。
```javascript
var change = {
object: {...},
type: 'update',
name: 'p2',
oldValue: 'Property 2'
}
```
Object.observe方法目前共支持监听六种变化。
@ -919,9 +911,7 @@ Object.observe方法目前共支持监听六种变化。
Object.observe方法还可以接受第三个参数用来指定监听的事件种类。
```javascript
Object.observe(o, observer, ['delete']);
```
上面的代码表示只在发生delete事件时才会调用回调函数。
@ -929,9 +919,7 @@ Object.observe(o, observer, ['delete']);
Object.unobserve方法用来取消监听。
```javascript
Object.unobserve(o, observer);
```
注意Object.observe和Object.unobserve这两个方法不属于ES6而是属于ES7的一部分。不过Chrome浏览器从33版起就已经支持。

View File

@ -28,8 +28,8 @@
## 语法点
- Kyle Simpson, [For and against `let`](http://davidwalsh.name/for-and-against-let): 讨论let命令的作用域
- kangax, [Why `typeof` is no longer “safe”](http://es-discourse.com/t/why-typeof-is-no-longer-safe/15): 讨论在块级作用域内let命令的变量声明和赋值的行为
- Kyle Simpson, [For and against let](http://davidwalsh.name/for-and-against-let): 讨论let命令的作用域
- kangax, [Why typeof is no longer “safe”](http://es-discourse.com/t/why-typeof-is-no-longer-safe/15): 讨论在块级作用域内let命令的变量声明和赋值的行为
- Axel Rauschmayer, [Variables and scoping in ECMAScript 6](http://www.2ality.com/2015/02/es6-scoping.html): 讨论块级作用域与let和const的行为
- Nick Fitzgerald, [Destructuring Assignment in ECMAScript 6](http://fitzgeraldnick.com/weblog/50/): 详细介绍解构赋值的用法
- Nicholas C. Zakas, [Understanding ECMAScript 6 arrow functions](http://www.nczonline.net/blog/2013/09/10/understanding-ecmascript-6-arrow-functions/)
@ -122,6 +122,7 @@
- Axel Rauschmayer, [Classes in ECMAScript 6 (final semantics)](http://www.2ality.com/2015/02/es6-classes-final.html): Class语法的详细介绍和设计思想分析
- Maximiliano Fierro, [Declarative vs Imperative](http://elmasse.github.io/js/decorators-bindings-es7.html): Decorators和Mixin介绍
- Addy Osmani, [Exploring ES2016 Decorators](https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841): Decorator的深入介绍
- Sebastian McKenzie, [Allow decorators for functions as well](https://github.com/wycats/javascript-decorators/issues/4): 为什么修饰器不能用于函数
- Maximiliano Fierro, [Traits with ES7 Decorators](http://cocktailjs.github.io/blog/traits-with-es7-decorators.html): Trait的用法介绍
## 模块