diff --git a/docs/proxy.md b/docs/proxy.md index 83bbcad..8f5b329 100644 --- a/docs/proxy.md +++ b/docs/proxy.md @@ -1036,3 +1036,43 @@ Reflect.defineProperty(obj, name, desc); ``` 上面代码中,`Reflect.defineProperty`方法的作用与`Object.defineProperty`是一样的,都是为对象定义一个属性。但是,`Reflect.defineProperty`方法失败时,不会抛出错误,只会返回`false`。 + +## 实例:使用 Proxy 实现观察者模式 + +观察者模式(Observer mode)指的是函数自动观察数据对象,一旦对象有变化,函数就会自动执行。 + +```javascript +const person = observable({ + name: '张三', + age: 20 +}); + +function print() { + console.log(`${person.name}, ${person.age}`) +} + +observe(print); +person.name = '李四'; +// 输出 +// 李四, 20 +``` + +上面代码中,数据对象`person`是观察目标,函数`print`是观察者。一旦数据对象发生变化,`print`就会自动执行。 + +下面,使用 Proxy 写一个观察者模式的最简单实现,即实现`observable`和`observe`这两个函数。思路是`observable`函数返回一个原始对象的 Proxy 代理,拦截赋值操作,触发充当观察者的各个函数。 + +```javascript +const queuedObservers = new Set(); + +const observe = fn => queuedObservers.add(fn); +const observable = obj => new Proxy(obj, {set}); + +function set(target, key, value, receiver) { + const result = Reflect.set(target, key, value, receiver); + queuedObservers.forEach(observer => observer()); + return result; +} +``` + +上面代码中,先定义了一个`Set`集合,所有观察者函数都放进这个集合。然后,`observable`函数返回原始对象的代理,拦截赋值操作。拦截函数`set`之中,会自动执行所有观察者。 + diff --git a/docs/reference.md b/docs/reference.md index 2b5c5f4..c8ad598 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -94,20 +94,6 @@ - Axel Rauschmayer, [ES proposal: Object.getOwnPropertyDescriptors()](http://www.2ality.com/2016/02/object-getownpropertydescriptors.html) - TC39, [Object.getOwnPropertyDescriptors Proposal](https://github.com/tc39/proposal-object-getownpropertydescriptors) -## Proxy和Reflect - -- Nicholas C. Zakas, [Creating defensive objects with ES6 proxies](http://www.nczonline.net/blog/2014/04/22/creating-defensive-objects-with-es6-proxies/) -- Axel Rauschmayer, [Meta programming with ECMAScript 6 proxies](http://www.2ality.com/2014/12/es6-proxies.html): Proxy详解 -- Daniel Zautner, [Meta-programming JavaScript Using Proxies](http://dzautner.com/meta-programming-javascript-using-proxies/): 使用Proxy实现元编程 -- Tom Van Cutsem, [Harmony-reflect](https://github.com/tvcutsem/harmony-reflect/wiki): Reflect对象的设计目的 -- Tom Van Cutsem, [Proxy Traps](https://github.com/tvcutsem/harmony-reflect/blob/master/doc/traps.md):Proxy拦截操作一览 -- Tom Van Cutsem, [Reflect API](https://github.com/tvcutsem/harmony-reflect/blob/master/doc/api.md) -- Tom Van Cutsem, [Proxy Handler API](https://github.com/tvcutsem/harmony-reflect/blob/master/doc/handler_api.md) -- Nicolas Bevacqua, [ES6 Proxies in Depth](http://ponyfoo.com/articles/es6-proxies-in-depth) -- Nicolas Bevacqua, [ES6 Proxy Traps in Depth](http://ponyfoo.com/articles/es6-proxy-traps-in-depth) -- Nicolas Bevacqua, [More ES6 Proxy Traps in Depth](http://ponyfoo.com/articles/more-es6-proxy-traps-in-depth) -- Axel Rauschmayer, [Pitfall: not all objects can be wrapped transparently by proxies](http://www.2ality.com/2016/11/proxying-builtins.html) - ## Symbol - Axel Rauschmayer, [Symbols in ECMAScript 6](http://www.2ality.com/2014/12/es6-symbols.html): Symbol简介 @@ -126,6 +112,21 @@ - Jason Orendorff, [ES6 In Depth: Collections](https://hacks.mozilla.org/2015/06/es6-in-depth-collections/):Set和Map结构的设计思想 - Axel Rauschmayer, [Converting ES6 Maps to and from JSON](http://www.2ality.com/2015/08/es6-map-json.html): 如何将Map与其他数据结构互相转换 +## Proxy和Reflect + +- Nicholas C. Zakas, [Creating defensive objects with ES6 proxies](http://www.nczonline.net/blog/2014/04/22/creating-defensive-objects-with-es6-proxies/) +- Axel Rauschmayer, [Meta programming with ECMAScript 6 proxies](http://www.2ality.com/2014/12/es6-proxies.html): Proxy详解 +- Daniel Zautner, [Meta-programming JavaScript Using Proxies](http://dzautner.com/meta-programming-javascript-using-proxies/): 使用Proxy实现元编程 +- Tom Van Cutsem, [Harmony-reflect](https://github.com/tvcutsem/harmony-reflect/wiki): Reflect对象的设计目的 +- Tom Van Cutsem, [Proxy Traps](https://github.com/tvcutsem/harmony-reflect/blob/master/doc/traps.md): Proxy拦截操作一览 +- Tom Van Cutsem, [Reflect API](https://github.com/tvcutsem/harmony-reflect/blob/master/doc/api.md) +- Tom Van Cutsem, [Proxy Handler API](https://github.com/tvcutsem/harmony-reflect/blob/master/doc/handler_api.md) +- Nicolas Bevacqua, [ES6 Proxies in Depth](http://ponyfoo.com/articles/es6-proxies-in-depth) +- Nicolas Bevacqua, [ES6 Proxy Traps in Depth](http://ponyfoo.com/articles/es6-proxy-traps-in-depth) +- Nicolas Bevacqua, [More ES6 Proxy Traps in Depth](http://ponyfoo.com/articles/more-es6-proxy-traps-in-depth) +- Axel Rauschmayer, [Pitfall: not all objects can be wrapped transparently by proxies](http://www.2ality.com/2016/11/proxying-builtins.html) +- Bertalan Miklos, [Writing a JavaScript Framework - Data Binding with ES6 Proxies](https://blog.risingstack.com/writing-a-javascript-framework-data-binding-es6-proxy/): 使用 Proxy 实现观察者模式 + ## Iterator - Mozilla Developer Network, [Iterators and generators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators) diff --git a/docs/style.md b/docs/style.md index 5f20ff2..37f1ae4 100644 --- a/docs/style.md +++ b/docs/style.md @@ -6,7 +6,7 @@ ## 块级作用域 -**(1)let取代var** +**(1)let 取代 var** ES6提出了两个新的声明变量的命令:`let`和`const`。其中,`let`完全可以取代`var`,因为两者语义相同,而且`let`没有副作用。 @@ -41,7 +41,9 @@ if(true) { **(2)全局常量和线程安全** -在`let`和`const`之间,建议优先使用`const`,尤其是在全局环境,不应该设置变量,只应设置常量。这符合函数式编程思想,有利于将来的分布式运算。 +在`let`和`const`之间,建议优先使用`const`,尤其是在全局环境,不应该设置变量,只应设置常量。 + +`const`优于`let`有几个原因。一个是`const`可以提醒阅读程序的人,这个变量不应该改变;另一个是`const`比较符合函数式编程思想,运算不改变值,只是新建值,而且这样也有利于将来的分布式运算;最后一个原因是 JavaScript 编译器会对`const`进行优化,所以多使用`const`,有利于提供程序的运行效率,也就是说`let`和`const`的本质区别,其实是编译器内部的处理不同。 ```javascript // bad diff --git a/sidebar.md b/sidebar.md index ce4ede5..cd993b5 100644 --- a/sidebar.md +++ b/sidebar.md @@ -16,8 +16,8 @@ 1. [函数的扩展](#docs/function) 1. [对象的扩展](#docs/object) 1. [Symbol](#docs/symbol) -1. [Proxy和Reflect](#docs/proxy) 1. [Set和Map数据结构](#docs/set-map) +1. [Proxy和Reflect](#docs/proxy) 1. [Iterator和for...of循环](#docs/iterator) 1. [Generator函数](#docs/generator) 1. [Promise对象](#docs/promise)