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] = newVal
        console.log('set',target,key,receiver)
		//下面3个等式告诉我们 target就是源对象(obj),receiver就是接收对象/代理对象(objProxy)	
        console.log(target === receiver)	//false
        console.log(target === obj)	//true
        console.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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/343388.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[Linux]HTTP状态响应码列举

1xx:信息响应类,表示接收到请求并且继续处理 2xx:处理成功响应类,表示动作被成功接收、理解和接受 3xx:重定向响应类,为了完成指定的动作,必须接受进一步处理 4xx:客户端错误&#x…

7.Feign远程调用

2.Feign远程调用 先来看我们以前利用RestTemplate发起远程调用的代码: 存在下面的问题: •代码可读性差,编程体验不统一 •参数复杂URL难以维护 Feign是一个声明式的http客户端,官方地址:https://github.com/OpenF…

RabbitMQ消息应答与发布

消息应答 RabbitMQ一旦向消费者发送了一个消息,便立即将该消息,标记为删除. 消费者完成一个任务可能需要一段时间,如果其中一个消费者处理一个很长的任务并仅仅执行了一半就突然挂掉了,在这种情况下,我们将丢失正在处理的消息,后续给消费者发送的消息也就无法接收到了. 为了…

【BIAI】Lecture 6 - Somatosensory systems

Lecture 6- Somatosensory systems 专业术语 somatosensory system 体感系统 Thermoreceptors 温度感受器 Photoreceptors 光感受器 Chemoreceptoprs 化学感受器 hairy skin 毛发皮肤 glabrous skin 光滑皮肤 sensory receptors 感觉受体 dermal 真皮的 epidermal 表皮的 axon…

外包干了2个多月,技术退步明显。。。。。

先说一下自己的情况,本科生,19年通过校招进入广州某软件公司,干了接近3年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

创建高打开率邮件标题的技巧:吸引潜在客户的秘诀

邮件打开率是指什么? 邮件打开率是指打开邮件的人数占发送的收件人总人数的比例。 邮件的打开率是衡量营销效果如何的一个非常重要的指标,而邮件标题又是影响邮件打开率非常重要的因素之一。所以,我们要要重视邮件标题。那我们应该如何编辑…

《移动通信原理与应用》——QPSK调制解调仿真

目录 一、QPSK调制与解调流程图: 二、仿真运行结果: 三、MATLAB仿真代码: 一、QPSK调制与解调流程图: QPSK调制流程图: QPSK解调流程图: 二、仿真运行结果: 1、Figure1:为发送端比特流情…

深入了解WPF控件:常用属性与用法(七)

掌握WPF控件:熟练常用属性(七) Menu 用于为应用程序指定命令或选项的项列表。它允许用户通过选择不同的菜单项来执行不同的命令或操作。 每个 Menu 可以包含多个 MenuItem 控件。 每个 MenuItem 都可以调用命令或调用 Click 事件处理程序。…

竞赛保研 电影评论情感分析 - python 深度学习 情感分类

1 前言 🔥学长分享优质竞赛项目,今天要分享的是 🚩 GRU的 电影评论情感分析 - python 深度学习 情感分类 🥇学长这里给一个题目综合评分(每项满分5分) 难度系数:3分工作量:3分创新点:4分 这…

vue3-组件基础

什么是组件 组件允许我们将 UI 划分为独立的、可重用的部分,并且可以对每个部分进行处理。在实际应用中,组件常常被组织成层层嵌套的树状结构。 定义一个组件 我们一般会将 Vue 组件定义在一个单独的 .vue 文件中,这被叫做单文件组件 (简称…

【加速】Ubuntu 22.04 LTS Steam++ Watt Toolkit 加速 github

项目地址 SteamTools: 🛠「Watt Toolkit」是一个开源跨平台的多功能 Steam 工具箱。 下载linux版本 wget https://gitee.com/rmbgame/SteamTools/releases/download/3.0.0-rc.3/Steam%20%20_v3.0.0-rc.3_linux_x64.tgz 解压到/opt/steam sudo mkdir /opt/steam…

【C语言】扫雷游戏完整代码实现

目录 1.game.h 2.game.c 3.progress.c 4.运行结果 1.game.h #define _CRT_SECURE_NO_WARNINGS#include <string.h> #include <stdio.h> #include <time.h> #include<stdlib.h>#define ROW 9 #define COL 9 #define ROWS 11 #define COLS 11 #defin…

ctfshow-反序列化(web271-web276)

目录 web271 web272-273 web274 web275 web276 为什么不用分析具体为什么能成功 ,后面会有几个专题 会对php框架进行更深入的了解 这里面会专门的研究 为什么能够实现RCE 前面作为初步的熟悉 首先知道一下他的框架 知道框架的风格 知道啥版本可以用什么来打 首先先不用太研…

CopyOnWriteArrayList源码

CopyOnWriteArrayList源码 介绍 CopyOnWriteArrayList底层采用数组对元素进行存储&#xff0c;采用写时复制技术:写的时候加锁&#xff0c;将原数组拷贝一份&#xff0c;对新数组进行操作&#xff0c;新数组长度为原数组长度1,写入完成后替换原数组&#xff0c;原数组使用vol…

【Linux】Vagrant搭建Linux环境

1. Vagrant Vagrant是一个基于Ruby的工具&#xff0c;用于创建和部署虚拟化开发环境。它使用Oracle的开源VirtualBox虚拟化系统&#xff0c;使用 Chef创建自动化虚拟环境。 1.1 安装Vagrant 从Vagrant官网下载安装包&#xff0c;执行安装。 1.2 安装VirtualBox 从官网下载…

【linux基础】linux root用户密码忘记解决方式

方式一&#xff1a;进入单用户模式 1.开启虚拟机的时候&#xff0c;按下“e”健进入用户引导界面 2.再按下“e”&#xff0c;进入内核的编辑 3.找到kernel开头的选项&#xff0c;再次按下“e” 4. 输入 5. 按下“b”&#xff0c;启动 6. 启动后&#xff0c;输入passwd&#xf…

Git的管理操作

目录 前言 认识工作区、暂存区、版本库 小结&#xff1a; 使用场景--1&#xff1a; git log&#xff1a; 查看.git文件&#xff1a; 使用场景--2&#xff1a; git status&#xff1a; git diff&#xff1a; 进行提交&#xff1a; 总结&#xff1a; 版本回退 退…

搜索(2):宽度优先搜索

目录 1.宽度优先搜索(BFS) 2.马的遍历(经典宽搜) 2.1 建图 2.2 宽搜 2.3 完整代码 3.洛谷BFS 3.1 奇怪的电梯 3.2 Meteor Shower 1.宽度优先搜索(BFS) 宽搜从根进入&#xff0c;向下逐层扩展&#xff0c;逐层访问 宽搜是通过队列来实现的&#xff0c;用queue创建一个队列…

DataStream API(输出算子)

源算子 源算子 转换算子 转换算子 输出算子 1.连接到外部系统 连接外部系统是计算机科学和信息技术领域中常见的一个任务&#xff0c;通常涉及到与外部数据源或服务进行交互。具体的方法和工具会根据不同的应用场景和需求而有所不同。以下是一些常见的连接外部系统的方法&…

什么是 Web3.0

什么是Web3.0 对于 Web3.0 的解释网上有很多&#xff0c;目前来说 Web3.0 是一个趋势&#xff0c;尚未有明确的定义。我们今天讨论下几个核心的点&#xff0c;就能很好的理解 Web3.0 要解决哪些问题 谁创造数据&#xff0c;这里的数据可以是一篇博客&#xff0c;一段视频&…