definePropety

ES5 提供了 Object.defineProperty 方法,该方法可以在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。

语法

1
Object.defineProperty(obj, prop, descriptor);

参数

  1. obj: 要在其上定义属性的对象。
  2. prop: 要定义或修改的属性的名称。
  3. descriptor: 将被定义或修改的属性的描述符。

第三个参数 descriptor 所表示的属性描述符有两种形式:数据描述符存取描述符
属性描述符descriptor.png

用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var obj = {},
value = 9;
Object.defineProperty(obj, "age", {
get: function () {
console.log("get");
return value;
},
set: function (val) {
console.log("set");
value = val;
},
});
console.log(obj.age); // get 9
obj.age = 18; // set
console.log(obj.age); // get 18

proxy

使用 defineProperty 只能重定义属性的读取(get)和设置(set)行为,到了 ES6,提供了 Proxy,可以重定义更多的行为,比如 in、delete、函数调用等更多行为。

语法

1
var proxy = new Proxy(target, handler);

参数

proxy 对象的所有用法,都是上面这种形式,不同的只是 handler 参数的写法。其中,new Proxy()表示生成一个 Proxy 实例,target 参数表示所要拦截的目标对象,handler 参数也是一个对象,用来定制拦截行为。

用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var proxy = new Proxy(
{},
{
get: function (obj, prop) {
console.log("设置 get 操作");
return obj[prop];
},
set: function (obj, prop, value) {
console.log("设置 set 操作");
obj[prop] = value;
},
}
);

proxy.time = 35; // 设置 set 操作

console.log(proxy.time); // 设置 get 操作 // 35

除了 get 和 set 之外,proxy 可以拦截多达 13 种操作,比如 has(target, propKey),可以拦截 propKey in proxy 的操作,返回一个布尔值。

1
2
3
4
5
6
7
8
9
10
11
12
// 使用 has 方法隐藏某些属性,不被 in 运算符发现
var handler = {
has(target, key) {
if (key[0] === "_") {
return false;
}
return key in target;
},
};
var target = { _prop: "foo", prop: "foo" };
var proxy = new Proxy(target, handler);
console.log("_prop" in proxy); // false