JS高级 之 Proxy-Reflect 使用详解
目录
一、以前监听对象 Object.defineProperty() - JavaScript | MDN
1. 使用Object.defineProperty
2. 缺点
二、Proxy Proxy - JavaScript | MDN
1. 基本使用
2. set和get捕获器
2. Proxy所有捕获器
三、Reflect Reflect - JavaScript | MDN
1. 作用
2. 出现的理由
3. 和Object的区别
4. Reflect的常见方法
5. Reflect和Proxy搭配来使用
6. Reflect和Construct搭配来使用
一、以前监听对象 Object.defineProperty() - JavaScript | MDN
1. 使用Object.defineProperty
const obj = {name: 'star',age: 14
};
for (const [key, value] of Object.entries(obj)) {let _value = value;// 监听Object.defineProperty(obj, key, {enumerable: true,set(value) {console.log('set:', value);// 通过闭包使用外部的值, obj.name = value => 这样会死循环,注意_value = value;},get() {console.log('get:', _value);// 通过闭包使用外部的值, obj.name = value => 这样会死循环,注意return _value;}});
}
// get监听到
console.log(obj.name);
// set监听到
obj.name = 'coder';
// get监听到
console.log(obj.name);
2. 缺点
1. Object.defineProperty设计的初衷,不是为了去监听截止一个对象中所有的属性的
2. 想监听更加丰富的操作,比如新增属性、删除属性,那么Object.defineProperty是无能为力的
二、Proxy Proxy - JavaScript | MDN
在ES6中,新增了一个Proxy类,是用于创建一个代理的
- 也就是说,如果希望监听一个对象的相关操作,可以先创建一个代理对象(Proxy对象)
- 之后对该对象的所有操作,都通过代理对象来完成,代理对象可以监听想要对原对象进行哪些操作
- 想要侦听某些具体的操作,那么就可以在handler中添加对应的捕捉器(Trap)
1. 基本使用
const obj = {name: 'star',age: 18,height: 1.88
};const objProxy = new Proxy(obj, {});
2. set和get捕获器
set函数有四个参数:
- target:目标对象(侦听的对象)
- property:将被设置的属性key
- value:新属性值
- receiver:调用的代理对象
get函数有三个参数:
- target:目标对象(侦听的对象)
- property:被获取的属性key
- receiver:调用的代理对象
const obj = {name: 'star',age: 18,height: 1.88
};
// 1. 创建proxy代理对象
const objProxy = new Proxy(obj, {// 2. 设置set捕获器set(target, key, newValue) {console.log(`监听到${key}设置值`);target[key] = newValue;},// 3. 设置get捕获器get(target, key) {console.log(`监听到${key}获取值`);return target[key];}
});
// 触发get捕获器
console.log(objProxy.name);
// 触发set捕获器
objProxy.name = 'coder';
// 触发get捕获器
console.log(objProxy.name);// 4. 新增属性也能被监听到
objProxy.address = '广州市';
// 触发set捕获器
console.log(objProxy.address);
// 添加成功
console.log(obj); // {name: 'coder', age: 18, height: 1.88, address: '广州市'}
2. Proxy所有捕获器
- handler.getPrototypeOf()
- Object.getPrototypeOf 方法的捕捉器,获取对象的原型
- handler.setPrototypeOf()
- Object.setPrototypeOf 方法的捕捉器,设置对象的原型
- handler.isExtensible()
- Object.isExtensible 方法的捕捉器,判断是否可以新增属性
- handler.preventExtensions()
- Object.preventExtensions 方法的捕捉器,阻止对象扩展
- handler.getOwnPropertyDescriptor()
- Object.getOwnPropertyDescriptor 方法的捕捉器,获取自己的属性描述符
- handler.defineProperty()
- Object.defineProperty 方法的捕捉器,定义自己的属性描述符
- handler.ownKeys()
- Object.getOwnPropertyNames 方法和Object.getOwnPropertySymbols 方法的捕捉器
- handler.has()
- in 操作符的捕捉器, 用in操作符判断的时候
- handler.get()
- 属性读取操作的捕捉器
- handler.set()
- 属性设置操作的捕捉器
- handler.deleteProperty()
- delete 操作符的捕捉器
- handler.apply()
- 函数调用操作的捕捉器,函数调用apply时触发
- handler.construct()
- new 操作符的捕捉器,函数被new时触发
三、Reflect Reflect - JavaScript | MDN
Reflect也是ES6新增的一个API,是一个对象,意思是反射
1. 作用
- 主要提供了很多操作JavaScript对象的方法,有点像Object中操作对象的方法
- Reflect.getPrototypeOf(target) 类似于 Object.getPrototypeOf()
- Reflect.defineProperty(target, propertyKey, attributes) 类似于Object.defineProperty()
2. 出现的理由
比较 Reflect 和 Object 方法 - JavaScript | MDN
- 是因为在早期的ECMA规范中没有考虑到这种对 对象本身 的操作如何设计会更加规范,所以将这些API放到了Object上面
- 但是Object作为一个构造函数,这些操作实际上放到它身上并不合适
- 同时Object作为所有类的父类,导致Object非常的臃肿
- 另外还包含一些类似in、delete的操作符,有点奇怪
- ----------------------------------------------
- 所以ES6新增了Reflect,让对对象的操作全部集中到了Reflect对象上
- Reflect同时配合Proxy,可以做到不操作原对象
看文档~~~非常nice的东西
3. 和Object的区别
大部分操作完对象后都会返回bool值,用来告知是否操作成功
// 开启严格模式
'use strict';
const obj = {name: 'why',age: 18
};
Object.defineProperty(obj, 'name', {configurable: false
});// 用以前的方式进行操作
// 1. 不确定能否删除,如果这个对象定义过属性描述符configurable为false,那么就不能删除
// 严格模式下还会报错
delete obj.name;
// 2. 判断是否删除成功,需要这样判断,这样判断还不严谨,如果对象的隐式原型上或着之上有这个属性,那么就判断不成功
if (obj.name) {console.log('name没有删除成功');
} else {console.log('name删除成功');
}// 使用Reflect
// 1. 就算配置了不可删除,但是使用这个deleteProperty不会报错而导致卡在这
// 2. 删除成功或者失败会返回bool值,代码更加严谨
if (Reflect.deleteProperty(obj, 'name')) {console.log('name删除成功');
} else {console.log('name没有删除成功');
}console.log(obj);
4. Reflect的常见方法
是和Proxy是一一对应的,也是13个
- Reflect.getPrototypeOf(target)
- 类似于 Object.getPrototypeOf()
- Reflect.setPrototypeOf(target, prototype)
- 设置对象原型的函数. 返回一个 Boolean, 如果更新成功,则返回
true
- 设置对象原型的函数. 返回一个 Boolean, 如果更新成功,则返回
- Reflect.isExtensible(target)
- 类似于 Object.isExtensible()
- Reflect.preventExtensions(target)
- 类似于 Object.preventExtensions()。返回一个Boolean
- Reflect.getOwnPropertyDescriptor(target, propertyKey)
- 类似于 Object.getOwnPropertyDescriptor()。如果对象中存在该属性,则返回对应的属性描述符, 否则返回 undefined
- Reflect.defineProperty(target, propertyKey, attributes)
- 和 Object.defineProperty() 类似。如果设置成功就会返回 true
- Reflect.ownKeys(target)
- 返回一个包含所有自身属性(不包含继承属性)的数组。(类似于Object.keys(), 但不会受enumerable影响)
- Reflect.has(target, propertyKey)
- 判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同
- Reflect.get(target, propertyKey[, receiver])
- 获取对象身上某个属性的值,类似于 target[name]
- Reflect.set(target, propertyKey, value[, receiver])
- 将值分配给属性的函数。返回一个Boolean,如果更新成功,则返回true
- Reflect.deleteProperty(target, propertyKey)
- 作为函数的delete操作符,相当于执行 delete target[name]
- Reflect.apply(target, thisArgument, argumentsList)
- 对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和
Function.prototype.apply() 功能类似
- 对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和
- Reflect.construct(target, argumentsList[, newTarget])
- 对构造函数进行 new 操作,相当于执行 new target(...args)
5. Reflect和Proxy搭配来使用
主要目的 :
- 代码更规范、不直接操作原对象
- 用Proxy监听、用Reflect执行
- 执行完后还知道是否操作成功
const obj = {name: 'why',age: 18
};const objProxy = new Proxy(obj, {// 监听设置set(target, key, newValue) {// 以前写法,不好,不知是否操作成功// target[key] = newValue// 现在,nice!const isSuccess = Reflect.set(target, key, newValue);if (!isSuccess) {throw new Error(`set ${key} failure`);}},// 监听获取get(target, key) {// 不直接获取,使用Reflectreturn Reflect.get(target, key);},// 监听判断has(target, key) {console.log('has');// 不直接判断,使用Reflectreturn Reflect.has(target, key);}
});// 操作代理对象
objProxy.name = 'kobe'; // 触发set操作
console.log('name' in objProxy); // 触发set操作 true
console.log(obj); // {name: 'kobe', age: 18}
6. Reflect和Construct搭配来使用
// 父类
function Person(name, age) {this.name = name;this.age = age;
}
// 子类
function Student(name, age) {// 可以不使用构造函数继承 在babel中的源码中就做了类似的判断// Person.call(this, name, age)// 创建一个对象,该对象的隐式原型指向Student,同时使用Person的构造方法const _this = Reflect.construct(Person, [name, age], Student);return _this;
}// const stu = new Student("why", 18)
const stu = new Student('coder', 18);
console.log(stu); // Student {name: 'coder', age: 18}
console.log(stu.__proto__ === Student.prototype); // true
JS高级 之 Proxy-Reflect 使用详解相关推荐
- Proxy和Reflect内容详解
ES6中的Proxy和Reflect内容详解 监听对象的操作 我们先来看一个需求:有一个对象,我们希望监听这个对象中的属性被设置或获取的过程 通过我们前面所学的知识,能不能做到这一点呢? 其实是可以的 ...
- JS逆向之浏览器补环境详解
JS逆向之浏览器补环境详解 "补浏览器环境"是JS逆向者升职加薪的必备技能,也是工作中不可避免的操作. 为了让大家彻底搞懂 "补浏览器环境"的缘由及原理,本文将 ...
- node.js卸载、安装、配置详解
node.js卸载.安装.配置详解 一. node.js卸载 二.下载安装 2.1 下载 2.2 安装 2.2.1 选择msi安装 2.2.2 选择zip安装 三.配置 3.1 环境变量配置 3.2 ...
- JS ES6中export和import详解
1.Export 模块是独立的文件,该文件内部的所有的变量外部都无法获取.如果希望获取某个变量,必须通过export输出, // profile.js export var firstName = ' ...
- js中toString()和String()区别详解
转载自 js中toString()和String()区别详解 我们知道String()与 .toString()都是可以转换为字符串类型,但是String()与 .toString()的还是有区别的 ...
- java调用js匿名函数参数,js匿名函数作为函数参数详解
由衷的感叹,js真是烦. 学到现在,渐渐理解了什么是:语言都是通用的,没有好不好,只有擅长不擅长. 继承,多态,甚至指针,c能实现,c++,java有,javascript(和java是雷锋和雷峰塔的 ...
- vue在created调用点击方法_vue.js中created方法的使用详解
这次给大家带来vue.js中created方法的使用详解,使用vue.js中created方法的注意事项有哪些,下面就是实战案例,一起来看一下. 这是它的一个生命周期钩子函数,就是一个vue实例被生成 ...
- JS弹出窗口Window.Open详解
JS弹出窗口Window.Open详解 一.window.open()支持环境: JavaScript1.0+/JScript1.0+/Nav2+/IE3+/Opera3+ 二.基本语法: windo ...
- JS中的日期和时间详解
JS中的日期和时间详解 关于Date()构造函数 简单实例 用Date()构造函数创建时钟 关于Date()构造函数 Date()构造函数是javascript的核心语言部分,用来创建表示时间和日期的 ...
- easyui js解析字符串_js相关:详解Jquery Easyui的验证扩展
js相关:详解Jquery Easyui的验证扩展 发布于 2020-7-2| 复制链接 本文主要介绍了Jquery Easyui验证扩展,Easyui验证,Easyui校验,js正则表达式.具有一定 ...
最新文章
- 【机器学习PAI实践十二】机器学习实现男女声音识别分类(含语音特征提取数据和代码)
- python 判断变量是否是 None 的三种写法
- 漫画: 什么是外部排序?
- SUSE团队已将重心偏向GCC 7
- 【kali】kali设置burpsuite抓包dvwa
- textview 结束后释放_等待按键释放,你的代码如何写?
- Linux报文硬件时间戳,linux下修改时间戳
- 排序学习之---插入排序
- java dom读写xml文件_java通过dom读写xml文件
- 【Redis】Redis 乐观锁
- 15-07-08 数组-- 投票选班长
- 【PAT甲】1007 Maximum Subsequence Sum (25分),求最大字段和及区间
- 箴言录2014年4月19日
- keras读取训练好的模型参数并把参数赋值给其它模型
- 副业 | 程序员开启副业之路经验之谈!
- 网易企业邮箱如何设置反垃圾规则?【网易企业邮箱】
- Marlin固件的欢迎界面
- c++ vector容器emplace_back
- 微信小程序,高德地图
- U-BOOT 下载 GitHub