From 8843f242917f352ec6232c7b265964f1816b4b70 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Sat, 19 Sep 2015 12:07:45 +0800 Subject: [PATCH] edit proxy --- docs/proxy.md | 180 ++++++++++++++++++++++++++++++++++++++++++++++ docs/reference.md | 3 + 2 files changed, 183 insertions(+) diff --git a/docs/proxy.md b/docs/proxy.md index 5ee09fe..ecc39c7 100644 --- a/docs/proxy.md +++ b/docs/proxy.md @@ -395,6 +395,45 @@ var p = new Proxy(obj, { 上面代码中,`obj`对象禁止扩展,结果使用`has`拦截就会报错。 +### construct() + +`construct`方法用于拦截`new`命令。 + +```javascript +var handler = { + construct (target, args) { + return new target(...args); + } +} +``` + +下面是一个例子。 + +```javascript +var p = new Proxy(function() {}, { + construct: function(target, args) { + console.log('called: ' + args.join(', ')); + return { value: args[0] * 10 }; + } +}); + +new p(1).value +// "called: 1" +// 10 +``` + +如果`construct`方法返回的不是对象,就会抛出错误。 + +```javascript +var p = new Proxy(function() {}, { + construct: function(target, argumentsList) { + return 1; + } +}); + +new p() // 报错 +``` + ### deleteProperty() `deleteProperty`方法用于拦截`delete`操作,如果这个方法抛出错误或者返回`false`,当前属性就无法被`delete`命令删除。 @@ -489,6 +528,92 @@ var p = new Proxy({}, { for (var x in p) {} // 报错 ``` +### getOwnPropertyDescriptor() + +`getOwnPropertyDescriptor`方法拦截`Object.getOwnPropertyDescriptor`,返回一个属性描述对象或者`undefined`。 + +```javascript +var handler = { + getOwnPropertyDescriptor (target, key) { + if (key[0] === '_') { + return + } + return Object.getOwnPropertyDescriptor(target, key) + } +} +var target = { _foo: 'bar', baz: 'tar' }; +var proxy = new Proxy(target, handler); +Object.getOwnPropertyDescriptor(proxy, 'wat') +// undefined +Object.getOwnPropertyDescriptor(proxy, '_foo') +// undefined +Object.getOwnPropertyDescriptor(proxy, 'baz') +// { value: 'tar', writable: true, enumerable: true, configurable: true } +``` + +上面代码中,`handler.getOwnPropertyDescriptor`方法对于第一个字符为下划线的属性名会返回`undefined`。 + +### getPrototypeOf() + +`getPrototypeOf`方法主要用来拦截`Object.getPrototypeOf()`运算符,以及其他一些操作。 + +- `Object.prototype.__proto__` +- `Object.prototype.isPrototypeOf()` +- `Object.getPrototypeOf()` +- `Reflect.getPrototypeOf()` +- `instanceof`运算符 + +下面是一个例子。 + +```javascript +var proto = {}; +var p = new Proxy({}, { + getPrototypeOf(target) { + return proto; + } +}); +Object.getPrototypeOf(p) === proto // true +``` + +上面代码中,`getPrototypeOf`方法拦截`Object.getPrototypeOf()`,返回`proto`对象。 + +### isExtensible() + +`isExtensible`方法拦截`Object.isExtensible`操作。 + +```javascript +var p = new Proxy({}, { + isExtensible: function(target) { + console.log("called"); + return true; + } +}); + +Object.isExtensible(p) +// "called" +// true +``` + +上面代码设置了`isExtensible`方法,在调用`Object.isExtensible`时会输出`called`。 + +这个方法有一个强限制,如果不能满足下面的条件,就会抛出错误。 + +```javascript +Object.isExtensible(proxy) === Object.isExtensible(target) +``` + +下面是一个例子。 + +```javascript +var p = new Proxy({}, { + isExtensible: function(target) { + return false; + } +}); + +Object.isExtensible(p); // 报错 +``` + ### ownKeys() `ownKeys`方法用来拦截`Object.keys()`操作。 @@ -532,6 +657,61 @@ for (let key of Object.keys(proxy)) { // "baz" ``` +### preventExtensions() + +`preventExtensions`方法拦截`Object.preventExtensions()`。该方法必须返回一个布尔值。 + +这个方法有一个限制,只有当`Object.isExtensible(proxy)`为`false`(即不可扩展)时,`proxy.preventExtensions`才能返回true,否则会报错。 + +```javascript +var p = new Proxy({}, { + preventExtensions: function(target) { + return true; + } +}); + +Object.preventExtensions(p); // 报错 +``` + +上面代码中,`proxy.preventExtensions`方法返回`true`,但这时`Object.isExtensible(proxy)`会返回`true`,因此报错。 + +为了防止出现这个问题,通常要在`proxy.preventExtensions`方法里面,调用一次`Object.preventExtensions`。 + +```javascript +var p = new Proxy({}, { + preventExtensions: function(target) { + console.log("called"); + Object.preventExtensions(target); + return true; + } +}); + +Object.preventExtensions(p) +// "called" +// true +``` + +### setPrototypeOf() + +`setPrototypeOf`方法主要用来拦截`Object.setPrototypeOf`方法。 + +下面是一个例子。 + +```javascript +var handler = { + setPrototypeOf (target, proto) { + throw new Error('Changing the prototype is forbidden'); + } +} +var proto = {}; +var target = function () {}; +var proxy = new Proxy(target, handler); +proxy.setPrototypeOf(proxy, proto); +// Error: Changing the prototype is forbidden +``` + +上面代码中,只要修改`target`的原型对象,就会报错。 + ## Proxy.revocable() Proxy.revocable方法返回一个可取消的Proxy实例。 diff --git a/docs/reference.md b/docs/reference.md index a9578d4..99434a6 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -78,6 +78,9 @@ - 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) ## Symbol