Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ES6 之深入理解 Proxy 知识 #189

Open
felix-cao opened this issue Dec 4, 2020 · 0 comments
Open

ES6 之深入理解 Proxy 知识 #189

felix-cao opened this issue Dec 4, 2020 · 0 comments

Comments

@felix-cao
Copy link
Owner

felix-cao commented Dec 4, 2020

Proxy 用于修改某些操作的默认行为,被称为 powerful meta programming,有很多强大的用处,如拦截(intercept),重载(overload),VUE3 的响应式(reactivity)系统构建等.有了 Proxy 可以实现很多神奇的功能。

The Proxy object is used to define custom behavior for fundamental operations (e.g. property lookup, assignment, enumeration, function invocation, etc).–MDN

JavaScript 的新标准ECMAScript语法越来越规范,之前的一些坑,新的标准规范也开始慢慢填,加上babel的普及使用,我们可以多多拥抱新语法、特性,简洁代码,愉悦自己。

一、基础语法

  • ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例。
  • Proxy 构造函数接受两个参数,targethandler, target 表示所要拦截的目标对象, handler 对象表示定制的拦截行为
var proxy = new Proxy(target, handler);
  • 对象是如何产生的:new 操作符调用 ES6 原生的 Proxy 构造器创建的 Proxy 实例对象名称为 proxy,简单的说 Proxy 构造器产生了他的实例对象 proxy

三个对象:proxy 对象,目标拦截对象 target, 拦截行为配置对象 handler
ES6Proxy 从语言层面上约定了这三个对象之间的玩法

二、拦截行为配置对象不作为 {}

const target = {
  msg: "Felix",
};
const handler1 = {};

const proxy1 = new Proxy(target, handler1);
console.log(proxy1.msg); // Felix 
console.log(target.msg); // Felix
proxy1.msg = 'Felix Cao, update after set proxy1';
console.log(proxy1.msg); // Felix Cao, update after set proxy1'
console.log(target.msg); // Felix Cao, update after set proxy1'

跑一把上面的代码看一看

三、拦截 get 操作

get 方法用于拦截对象属性的读取操作,如proxy.foo和proxy['foo']。可以接受三个参数,依次为目标对象、属性名和 proxy 实例本身(严格地说,是操作行为所针对的对象),其中最后一个参数可选。

3.1、拦截对象的所有属性

const target = {
  msg: 'Felix',
  from: 'Github',
};
const handler2 = {
  get(target,propKey,receiver) {
    console.log('Intercepted')
    return 'Felix Cao'
  }
};
const proxy2 = new Proxy(target, handler2);
console.log(proxy2.from); // Felix Cao
console.log(proxy2.msg); // Felix Cao
console.log(proxy2.title); // Felix Cao
  • proxy2 对象中的所有属性的访问,都被 handler2 配置的 get 拦截,这肯定不是我们期望的。

跑一把上面的代码看一看

3.2、拦截指定的属性

const target = {
  msg: "Felix",
};
const handler3 = {
  get(target,propKey,receiver) {
    console.log(`Intercept propKey: ${propKey}`)
    if(propKey === 'name') {
    	return 'China';
    }
  }
};

const proxy3 = new Proxy(target, handler3);
console.log(proxy3.msg); // undefined
console.log(proxy3.name); // China

利用 Reflect.get 仅拦截指定的属性---修复2.2的 bug, 即在 if 条件表达式后下面的代码即可

return Reflect.get(...arguments);

跑一把

3.3. 拦截处理异常

const target = {
  msg: "Felix",
};
const handler4 = {
  get(target,propKey,receiver) {
    if(propKey in target) {
    	return target[propKey]
    }
    throw new Error(`The object doesn't have the property ${propKey}`);
  }
};

const proxy4 = new Proxy(target, handler4);
console.log(proxy4.msg); // Felix
console.log(proxy4.name); // Error

跑一把

3.4. 拦截数组

Proxy 可以直接操作数组

const target = [1,2,3];
const handler5 = {
  get(target,propKey,receiver) {
    console.log(`Get Intercepted the propKey: ${propKey}`)
    const index = Number(propKey);
    if( index > target.length - 1 || index < 0 ) {
    	console.log('Out of the Array');
    	return 'Error'
    }
    return Reflect.get(target, propKey);
  },
  
  set(target, propKey, value, receiver) {
     console.log(`Set Intercepted the propKey: ${propKey}`)
     return Reflect.set(target, propKey, value, receiver);
  }
};
const proxy5 = new Proxy(target, handler5);
console.log(proxy5[1]); // 2
console.log(proxy5[3]); // Error
console.log(proxy5[4]=8); // 8

跑一把

Reference

@felix-cao felix-cao changed the title ES6 之 深入理解 Proxy 知识 ES6 之深入理解 Proxy 知识 Dec 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant