Object.defineProperty、Proxy、Reflect-个人总结

2024-01-24 03:04

本文主要是介绍Object.defineProperty、Proxy、Reflect-个人总结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Object.defineProperty

前言

        用于给一个对象添加或者修改一个属性,返回操作后的对象。

        写法:Object.defineProperty(对象,属性,配置对象)

配置对象

        通过对配置对象不同的配置,可以将属性分为数据属性和存取属性。

        数据属性不包括get和set方法,包括value和writable属性;存取属性包括get和set方法,不能含有value和writable属性。即这四个具有一定的相斥性。

        无论是数据属性还是存取属性都会包含configurable和enumerable属性。

        具体看下图

【图来自王红元】 

解释下configurable、enumerable、writable三个属性

1、configurable:控制能否对属性描述符(也就是配置对象)的修改(false时会爆redefine的错误)能否删除该属性

2、enumerable:控制属性是否可以枚举。【forin会能遍历自身和原型上的枚举属性,Object.keys能遍历自身的枚举属性】

3、writable:控制属性值的修改,(注意是属性值,不是配置对象)

 这三个属性都是布尔类型,默认都是false。

应用

        vue2的响应式原理就是应用,在get和set时做对应的响应式处理。

注意

不要在set方法中直接修改对象的属性

        在set中直接修改对象的属性会触发“set陷阱”,陷入死循环。

        解决办法是:可以在Object.definproperty的外面定一个变量,set去修改这个变量,get去读取这个变量,以达到类似的效果,比如下方代码的val。

let obj = {name:'aa',age:12
}
Object.keys(key=>{let val = obj[key]	//闭包变量,不会随着遍历结束消失。又因为get也是读这个变量,看起来对象的属性值就变了Object.defineProperty(obj,key,{set(newVal){console.log('set',newVal)val = newVal// 不能直接obj[key] =newVal ,会死循环},get(){console.log('get')return val}})
})obj.name = 111
console.log(obj.age)

Proxy

前言

        Proxy能创建出一个代理对象,之后对源对象的操作,都可以通过这个代理对象完成,也就实现了监听整个对象的功能。        

         写法 : new Proxy(源对象,捕获器对象)

基本使用

 直接看下面一段包含set和get捕获器的代码。

let obj = {name:'aa',age:12
}
let objProxy = new Proxy(obj,{// 各种捕获器get(target,key,receiver){console.log('get',target,key,receiver)return target[key]},set(target,key,newVal,receiver){target[key] = newValconsole.log('set',target,key,receiver)//下面3个等式告诉我们 target就是源对象(obj),receiver就是接收对象/代理对象(objProxy)	console.log(target === receiver)	//falseconsole.log(target === obj)	//trueconsole.log(receiver === objProxy) //true}})
objProxy.name = 'rr'//修改代理后的对象

代码说明:

        get和set捕获器的入参第一个会拿到target(源对象),最后一个入参是receiver(代理对象)。

        set中对源对象的修改就直接修改target,而不用去改obj,并且不需要借助外部变量了,也不再陷入死循环。

        【触发捕获器需要修改代理对象,而不是源对象

其他捕获器

        上面的set和get捕获器就能实现Object.defineProperty的功能,并且更强大。下面介绍其他捕获器,总共13个。见下图。

【图来自王红元】 

总结:

触发的方法/操作捕获器名
Object.getPropertyOf()
拿对象的隐式原型
getPropertyOf()
Object.setPropertyOf()
设置对象的隐式原型
setPropertyOf()
Object.isExtensible()
用于判断对象是否可以拓展
Object.preventExtensions()能禁止拓展
isExtensiable()
Object.preventExtensions()
用于禁止往对象上添加属性,即禁止拓展
preventExtensions()
Object.getOwnPropertyDescriptor()
获取对象的属性描述符
getOwnPropertyDescriptor()
Object.defineProperty() 
用于设置对象属性
defineProperty()
Object.getOwnPropertyNames()
Object.getOwnPropertySymbols()
拿对象自身的普通属性和symbol属性名,
无论是否枚举
ownKeys()
in操作符has()
属性读取get()
属性设置set()
delete操作符deleteProperty()
函数调用的applyapply()
new操作符construct()

Object.defineProperty和Proxy区别

        他们都可以用于拦截和设置对象属性,但是Proxy提供了更多的拦截操作。Proxy可以拦截所有属性,包括新增的,而defineProperty只能拦截定义时的属性,还不能拦截delete属性。

Reflect

介绍

        Reflect是一个内置的全局对象。

        Reflect也有Proxy捕获器上那13个方法。见下图:

【图来时王红元】 

设计Reflect的目的:【ai回答:】

1. 将Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上。 现阶段,某些方法同时在Object和Reflect对象上部署,未来的新方法将只部署在Reflect对象上。

2. 修改某些Object方法的返回结果,让其变得更合理。 比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)则会返回false。

3. 让Object操作都变成函数行为。 某些Object操作是命令式,比如name in obj和delete obj[name],而Reflect有对应的方法Reflect.has(obj, name)和Reflect.deleteProperty(obj, name)。

4. Reflect对象的方法与Proxy对象的方法一一对应。 无论Proxy对象怎么修改默认行为,你总可以在Reflect上获取默认行为。

个人总结:之前Object太臃肿了,现在设计Reflect是为了规范js的对象操作。

补充

对象的限制方法

说明方法
禁止往对象添加属性,返回对象Object.preventExtensions(Obj)
禁止设置对象属性的配置 和 属性值的删除,就是将configurable设为falseObject.seal(obj)
禁止对象属性的修改,冻结对象,不允许修改属性值,是浅层冻结。Object.freeze(obj)

END

这篇关于Object.defineProperty、Proxy、Reflect-个人总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/638353

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

git使用的说明总结

Git使用说明 下载安装(下载地址) macOS: Git - Downloading macOS Windows: Git - Downloading Windows Linux/Unix: Git (git-scm.com) 创建新仓库 本地创建新仓库:创建新文件夹,进入文件夹目录,执行指令 git init ,用以创建新的git 克隆仓库 执行指令用以创建一个本地仓库的

二分最大匹配总结

HDU 2444  黑白染色 ,二分图判定 const int maxn = 208 ;vector<int> g[maxn] ;int n ;bool vis[maxn] ;int match[maxn] ;;int color[maxn] ;int setcolor(int u , int c){color[u] = c ;for(vector<int>::iter

整数Hash散列总结

方法:    step1  :线性探测  step2 散列   当 h(k)位置已经存储有元素的时候,依次探查(h(k)+i) mod S, i=1,2,3…,直到找到空的存储单元为止。其中,S为 数组长度。 HDU 1496   a*x1^2+b*x2^2+c*x3^2+d*x4^2=0 。 x在 [-100,100] 解的个数  const int MaxN = 3000

状态dp总结

zoj 3631  N 个数中选若干数和(只能选一次)<=M 的最大值 const int Max_N = 38 ;int a[1<<16] , b[1<<16] , x[Max_N] , e[Max_N] ;void GetNum(int g[] , int n , int s[] , int &m){ int i , j , t ;m = 0 ;for(i = 0 ;

go基础知识归纳总结

无缓冲的 channel 和有缓冲的 channel 的区别? 在 Go 语言中,channel 是用来在 goroutines 之间传递数据的主要机制。它们有两种类型:无缓冲的 channel 和有缓冲的 channel。 无缓冲的 channel 行为:无缓冲的 channel 是一种同步的通信方式,发送和接收必须同时发生。如果一个 goroutine 试图通过无缓冲 channel

9.8javaweb项目总结

1.主界面用户信息显示 登录成功后,将用户信息存储在记录在 localStorage中,然后进入界面之前通过js来渲染主界面 存储用户信息 将用户信息渲染在主界面上,并且头像设置跳转,到个人资料界面 这里数据库中还没有设置相关信息 2.模糊查找 检测输入框是否有变更,有的话调用方法,进行查找 发送检测请求,然后接收的时候设置最多显示四个类似的搜索结果

HomeBank:开源免费的个人财务管理软件

在个人财务管理领域,找到一个既免费又开源的解决方案并非易事。HomeBank&nbsp;正是这样一个项目,它不仅提供了强大的功能,还拥有一个活跃的社区,不断推动其发展和完善。 开源免费:HomeBank 是一个完全开源的项目,用户可以自由地使用、修改和分发。用户友好的界面:提供直观的图形用户界面,使得非技术用户也能轻松上手。数据导入支持:支持从 Quicken、Microsoft Money

java面试常见问题之Hibernate总结

1  Hibernate的检索方式 Ø  导航对象图检索(根据已经加载的对象,导航到其他对象。) Ø  OID检索(按照对象的OID来检索对象。) Ø  HQL检索(使用面向对象的HQL查询语言。) Ø  QBC检索(使用QBC(Qurey By Criteria)API来检索对象。 QBC/QBE离线/在线) Ø  本地SQL检索(使用本地数据库的SQL查询语句。) 包括Hibern