Proxy是什么?

Proxy可以理解为一个代理人,他代表了一个明星在微博上与粉丝互动。实际上,这个账号是由其他人或团队运营的,他们发表的微博就代表了明星本人的意思。这里的代理人就是一个JavaScript中的Proxy对象。

JavaScript对象函数

在JavaScript中,Proxy是ES6中提供的新的API,可以用来定义对象各种基本操作的自定义行为。这些行为被称为traps(陷阱),可以理解为针对对象各种行为的钩子。当我们需要对一些对象的行为进行控制时,Proxy将变得非常有效。

Proxy的语法如下:

```javascript

let target = {};

let handlers = {}; // do nothing

let proxy = new Proxy(target, handlers);

proxy.a = 123;

console.log(target.a); // 123

```

在第二个参数为空对象的情况下,基本可以理解为是对第一个参数做的一次浅拷贝。需要注意的是,Proxy必须是浅拷贝,如果是深拷贝则会失去了代理的意义。

Traps(各种行为的代理)

在Proxy中,我们可以通过定义不同的traps来实现对对象各种行为的控制。例如:

```javascript

let obj = {

_age: 18,

get age() {

return `I'm ${this._age} years old`;

},

set age(val) {

this._age = Number(val);

}

};

console.log(obj.age); // I'm 18 years old

obj.age = 19;

console.log(obj.age); // I'm 19 years old

```

在这个例子中,我们定义了一个名为age的getter和setter,用于获取和设置对象的_age属性。当我们访问或修改obj.age时,这些getter和setter会被触发。

然而,使用gettersetterkey这种方式有一些缺点:首先,我们需要手动定义每个属性的getter和setter;其次,如果我们需要对多个属性进行类似的处理,就需要重复编写相同的代码。这时,Proxy的优势就体现出来了。

以下是重构后的内容:

## 使用Proxy解决对象属性为undefined的问题

```js

let target = { age: 18, name: 'Niko Bellic' }

let handlers = {

get (target, property) {

return `${property}: ${target[property]}`

},

set (target, property, value) {

target[property] = value

}

}

let proxy = new Proxy(target, handlers)

proxy.age = 19 // age: 19

console.log(target.age, proxy.age) // 19, 19

console.log(target.name, proxy.name) // Niko Bellic, name: Niko Bellic

```

在上述代码中,我们使用了Proxy来解决对象属性为undefined的问题。通过定义handlers对象,我们在set和get方法中对target对象进行了相应的操作。在set方法中,我们将value赋值给target[property],从而解决了属性值为undefined的问题。在get方法中,我们返回了property和对应的值,从而实现了属性值的访问。最后,我们创建了一个proxy实例,并对其进行了操作。

以下是重构后的代码,保持了原有的结构:

(() => {

let target = {};

let handlers = {

get: (target, property) => {

target[property] = (property in target) ? target[property] : {};

if (typeof target[property] === 'object') {

return new Proxy(target[property], handlers);

}

return target[property];

},

};

let proxy = new Proxy(target, handlers);

// z in proxy.x.y is false (actually this step has created an x.y property for `target`)

console.log('z' in proxy.x.y); // false

// proxy.x.y.z = 'hello'

// console.log('z' in proxy.x.y) is true

// console.log(target.x.y.z) // hello

})();

getgetkeytargetkeykeycannotgetxxxfromundefinedkeyinget普通函数与构造函数的兼容处理classES5newclassES5thisapplytrap

```javascriptclass Test {

constructor(a, b) {

console.log('constructor', a, b);

}

}

// Test(1, 2) // throw an error

let proxyClass = new Proxy(Test, {

apply: function (target, thisArg, argumentsList) {

// 如果想要禁止使用非new的方式来调用函数,直接抛出异常即可

// throw new Error(`Function ${target.name} cannot be invoked without 'new'`)

return new (target.bind(thisArg, ...argumentsList))();

},

});

proxyClass(1, 2); // constructor 1 2

applyClassapplynew

newtrapconstruct

function add(a, b) {

return a + b;

}

let proxy = new Proxy(add, {

construct: function (target, argumentsList, newTarget) {

throw new Error(`Function ${target.name} cannot be invoked with 'new'`);

},

});

proxy(1, 2); // 3 new proxy(1, 2) // throw an error

```

```javascriptlet handlers = {

get(target, property) {

if (!target.init) {

// 初始化对象

['GET', 'POST'].forEach(method => {

target[method] = (url, params = {}) => {

return fetch(url, {

headers: {

'content-type': 'application/json'

},

mode: 'cors',

credentials: 'same-origin',

method,

...params

}).then(response => response.json())

}

})

}

return target[property]

}

}

let API = new Proxy({}, handlers)

await API.GET('XXX')

await API.POST('XXX', { body: JSON.stringify({ name: 1 }) })

```

Proxy 是 ES6 中提供的新的 API,可以用来定义对象各种基本操作的自定义行为。Proxy 可以拦截 JS 引擎内部目标的底层对象操作,这些底层操作被拦截后会触发响应特定操作的陷阱函数(traps),对于别人封装好的对象或内建对象,都可以自定义操作。

下面是一个使用 Proxy 自定义 trap 的例子:

```javascript

let assert = new Proxy({}, { set (target, message, value) { if (!value) console.error(message) } });

assert['Isn\\'t true'] = false; // Error: Isn\\'t true

assert['Less than 18'] = 18 >= 19; // Error: Less than 18

```