代理与Reflect反射

属性描述符

Proprety Descriptor 属性描述符 用于描述一个属性的相关信息

1.Object.getOwnPropertyDescriptor(对象,属性名)

可以得到一个对象的 某个属性的属性描述符 

  Object.getOwnPropertyDescriptors(对象)

 可以得到某个对象的所有属性描述符

如果需要为某个对象添加属性或修改属性时,配置其属性描述符,可以使用

Object.definePropertie(对象、属性、描述符 )

Object.definePropertie(obj, 'a', { configurable: false })

 存取器属性

  • 属性描述符中,如果配置了get  set中任何一个,则该属性不再是一个普通属性,而变成存储器属性
  • get、set配置均为函数,如果一个属性是存储器属性,则读取该属性时,会运行get方法,将get方法得到的返回值作为属性值
  • 如果给该属性赋值,则会运行set方法
  • 存取器属性最大的意义,在于可以控制属性的读取和赋值
const obj = {
    b: 1
}
Object.defineProperty(obj, 'a', {
    get () {
        console.log("运行了属性的get函数")
    }, 
    set (val) {
        console.log("运行了属性的set函数", val)
    }
})
obj.a = obj.a + 1 
//set(obj.a+1) ==>set(get()+1)  
//1.需要先读取a值,但get()没有返回值 因此是undefined 
//2.undefined+1=NaN 
console.log(obj.a)

 

 1.使用其他属性值赋值。也可新增属性  _a

const obj = {
    b: 1
}
Object.defineProperty(obj, 'a', {
    get () {
        console.log("运行了属性的get函数")
        return obj._a //使用其他属性值
    }, set (val) {

        console.log("运行了属性的set函数", val)
        obj._a = val
    }
})
obj.a = 10 
console.log(obj.a)

 2.也可对赋值做自定义规范

Object.defineProperty(obj, 'a', {
    get () {
        console.log("运行了属性的get函数")
        return obj._a
    }, set (val) {
        if (typeof val !== 'number') {
            throw new TypeError('必须是一个数字')
        }
        if (val > 200) {
            val = 200
        }
        console.log("运行了属性的set函数", val)
        obj._a = val
    }
})
obj.a = 10000

Reflect 

1.reflect是什么?

reflect是一个内置的JS对象,它提供了一系列方法,可以让开发者通过调用这些方法,访问一些JS底层功能

由于类似于其他语、言的【 反射】,因此取名为Reflect

2.可以做什么?

可以实现 属性的赋值与取值、调用普通函数、调用构造函数、判断属性是否存在于对象中.etc

3.为什么还需要Reflect实现一次已有功能?

ES5提出重要理念  “减少魔法、让代码更加纯粹”,其很大程度受函数式编程影响

ES6进一步贯彻了该理念,它认为,对属性内存的控制、原型链的修改、函数的调用等,都属于底层实现,属于一种魔法,因此需要将他们提取出来形成一个正常的API ,高聚合到某个对象中,于是,造就了Reflect对象

4.提供了哪些API?

代理:Proxy

代理:提供了修改底层实现的方式

new Proxy(target,handler)

  • 代理一个目标
  • target:目标对象
  • handler:是一个普通对象,其中可以重写底层实现
  • 返回一个代理对象
const obj = {
    a: 1,
    b: 2
}
const proxy = new Proxy(obj, {
    set (target, propertyKey, value) {
        Reflect.set(target, propertyKey, value)
    },
    get (target, propertyKey) {
        if (Reflect.has(target, propertyKey)) {
            return Reflect.get(target, propertyKey)
        } else {
            return -1
        }
    },
    has (target, propertyKey) {
        return false
    }
})
proxy.a = 10
console.log(proxy.a)
console.log(proxy.d)

proxy应用——观察者模式

有一个对象,是观察者,他用于观察另外一个对象的属性值变化,当属性值变化后会收到一个通知,可能会做一些事 

以下方式不太好

function observer (target) {
    const ob = {}
    const div = document.getElementById('container')
    const props = Object.keys(target)
    for (const prop of props) {
        Object.defineProperty(ob, prop, {
            // 读属性值时,把目标值给你
            get () {
                return target[prop]
            },
            // 赋值时,给目标对象赋值,再渲染一次
            set (val) {
                target[prop] = val
                render()
            },
            enumerable: true
        })
    }
    // console.log(Object.getOwnPropertyDescriptors(ob))
    render()
    function render () {
        let html = ''
        for (const prop of Object.keys(ob)) {
            html += `<p><span>${prop}:</span><span>${ob[prop]}<span/></p>`
        }
        div.innerHTML = html
    }
    return ob
}
const target = {
    a: 1, b: 2
}
let obj = observer(target)
obj.a = 3
obj.b = 4

 一开始打印一下 ob,其中是不可枚举,不可被遍历的,所以要在属性配置定义一下该属性

一开始,页面呈现 a 、b值 

重新赋值后,页面也一起变化

两个对象内容相等,也造成内存的浪费 

使用代理实现,不会再浪费一块内存

function observer (target) {
    const div = document.getElementById('container')
    const proxy = new Proxy(
        target, {
        set (target, prop, value) {
            Reflect.set(target, prop, value)
        },
        get () {
            return Reflect.get(target, prop, value)
        }
    }
    )
    render()
    function render () {
        let html = ''
        for (const prop of Object.keys(target)) {
            html += `<p><span>${prop}:</span><span>${target[prop]}<span/></p>`
        }
        div.innerHTML = html

    }
    return proxy
}
const target = {
    a: 1, b: 2
}
let obj = observer(target)

 proxy应用——构造函数

1.原本构造函数

class User {
    constructor(firstName,
        lastName,
        age) {
        this.firstName = firstName
        this.lastName = lastName
        this.age = age
    }
}

2.使用代理方式偷懒 可以这么写

class User { }
function ConstructorProxy (Class, ...propNames) {
    // 重写类的底层实现
    return new Proxy(Class, {
        construct (target, argumentsList) {
            const obj = Reflect.construct(target, argumentsList)
            // 给构造函数对象加上这些属性
            propNames.forEach((name, i) => {
                obj[name] = argumentsList[i]
            })
            console.log('构造函数被调用了')
            return obj
        },
    })
}
const UserProxy = ConstructorProxy(
    User,
    'firstName',
    'lastName',
    'age'
)
// 通过代理告诉 构造函数有三个属性
const obj = new UserProxy('张', '三', 17)
console.log('obj1:', obj)

3.再加一个类也一样

class Monster { }
const monstorProxy = ConstructorProxy(
    Monster,
    'attack',
    'defence',
    'hp',
    'rate',
    'name'
)
const obj2 = new monstorProxy(10, 100, 3, 4, 'monster')
console.log('obj2:', obj2)

proxy应用——可验证的函数参数 

function sum (a, b) {
    return a + b
}
function validatorFunction (func, ...types) {
    const proxy = new Proxy(func, {
        apply (target, thisArgument, argumentList) {
            types.forEach((t, i) => {
                console.log(t, i)
                const arg = argumentList[i]
                console.log(arg)
                if (typeof arg !== t) {
                    throw new TypeError(`第${i + 1}个参数${argumentList[i]}不满足参数类型`)
                }
            })
            Reflect.apply(target, thisArgument, argumentList)
        }
    })
    return proxy
}
const sumProxy = validatorFunction(sum, "number", "number")
console.log(sumProxy(1, "2"))

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

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

相关文章

node.js基础-02

Author nodes&#xff1a;&#xff08;题记&#xff09; Hypertest Transfer protocol is very important to programming personnel。it doesnt matter if youre a front-end engineer or a back-end engineer.So,lets study it together. http协议对于编程工程师很重要&am…

基于华为云欧拉操作系统(HCE OS)单节点容器化部署(Prometheus、node-exporter、Grafana)应用性能监控平台

写在前面 博文内容为 华为云欧拉操作系统入门级开发者认证(HCCDA – Huawei Cloud EulerOS)实验笔记整理认证地址&#xff1a;https://edu.huaweicloud.com/certificationindex/developer/9bf91efb086a448ab4331a2f53a4d3a1内容涉及&#xff0c;HCE OS 容器化部署(Prometheus、…

【C++修行之道】(引用、函数提高)

目录 一、引用 1.1引用的基本使用 1.2 引用注意事项 1.3 引用做函数参数 1.4 引用做函数返回值 1.5 引用的本质 1.6 常量引用 1.7引用和指针的区别 二、函数提高 2.1 函数默认参数 2.2函数占位参数 2.3 函数重载 2.4函数重载注意事项 一、引用 1.1引用的基本使用 …

【canvas】获取鼠标点击位置坐标的颜色信息

在项目当中&#xff0c;要实现某业务需求例如PS魔棒功能时&#xff0c;则需要获取点击坐标的颜色信息。 功能不复杂&#xff0c;代码也很少&#xff0c;一看便知~~ 核心API为getImageData&#xff0c;传入4个参数&#xff0c;前2个为点击坐标xy&#xff0c;后2个都传1&#xf…

那些 C语言指针 你不知道的小秘密 (3)

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 我会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人能…

vscode连接ssh报错

关于vscode更新版本至1.86后&#xff0c;导致无法连接服务器问题的记录 原因&#xff1a;vscode1.86更新了对glibc的要求&#xff0c;需要最低2.28版本&#xff0c;导致各种旧版本的linux发行版&#xff08;比如最常见的centos 7&#xff09;都无法用remote-ssh来连接了&#…

Linux探秘之旅:透彻理解路径、命令与系统概念

目录 如何远程连接 远程登录简明指南 linux区别 1.严格区分大小写 2.linux的命令返回结果判断 3.如何查看网络信息 4.关于后缀名&#xff08;Linux不关心文件后缀&#xff09; 4.1 需要记忆的后缀 5.echo命令 6.linux一切皆文件 6.1比如磁盘的文件 6.2可执行文件 …

nginx + DNS域名解析

配置链接: Nginx 安装配置 | 菜鸟教程 安装完nginx后&#xff0c;访问&#xff1a; cd /usr/local/nginx/sbin/ 然后使用./nginx可使用nginx。 访问:http://服务器的ip地址后出现 因为访问IP地址很繁琐&#xff0c;需要记忆ip的数字地址&#xff0c;因此需要给它一个通俗的…

如何在Sprint中管理UI测试?

作为iOS团队&#xff0c;我们编写3种类型的UI测试。如果你问这些是什么&#xff1b;快照、冒烟和回归测试。那么这些测试到底是什么&#xff1f;让我们稍微谈谈这些。 快照测试快照测试是检查UI中的某些内容是否损坏的测试。 首先&#xff0c;它将所需的视图图像保存在某处&am…

Lombok 高级说明

优质博文&#xff1a;IT-BLOG-CN 一、痛点 【1】代码臃肿&#xff1a;POJO中的getter/setter/equals/hashcode/toString等&#xff1b; 【2】样板式代码&#xff1a;I/O流的关闭操作等&#xff1b; Lombok是一个可以通过注解简化Java代码开发的工具&#xff0c;能够在我们编…

string容器

1. string基本概念 1.1 本质&#xff1a; string是C风格的字符串&#xff0c;而string本质上是一个类 string和char * 区别&#xff1a; char * 是一个指针 string是一个类&#xff0c;类内部封装了char*&#xff0c;管理这个字符串&#xff0c;是一个char*型的容器。 1.2 特点…

书生·浦语大模型全链路开源体系

参考&#xff1a;https://www.bilibili.com/video/BV1Rc411b7ns/?spm_id_from333.788&vd_source3bbd0d74033e31cbca9ee35e111ed3d1 背景&#xff1a; 人工智能的发展从针对特定任务&#xff0c;用一个模型解决一个问题过渡到一个模型来应对多模态、多任务&#xff0c;大模…

K210如何下载程序

一、打开资料包里提供的K-Flash程序烧录软件 二、选择串口 三、选择波特率 四、选择In-Chip&#xff0c;烧录到Flash芯片里面&#xff0c;重新上电还会运行程序 五、如果选择In - Memory&#xff0c;这次可以运行&#xff0c;但下次重新上电就不会保持这次的程序了。 六、选择固…

springboot+vue居民小区设备报修系统

小区报修系统可以提高设施维护的效率&#xff0c;减少机构的人力物力成本&#xff0c;并使得维修人员可以更好地了解维护设备的情况&#xff0c;及时解决问题。 对于用户来说&#xff0c;报修系统也方便用户的维修请求和沟通&#xff0c;提高了用户的满意度和信任。其次小区报修…

在PyTorch中,如何查看深度学习模型的每一层结构?

这里写目录标题 1. 使用print(model)2. 使用torchsummary库3.其余方法&#xff08;可以参考&#xff09; 在PyTorch中&#xff0c;如果想查看深度学习模型的每一层结构&#xff0c;可以使用print(model)或者model.summary()&#xff08;如果你使用的是torchsummary库&#xff0…

网关中全局过滤器实现jwt校验

意味着有很多相同接口的实现类&#xff0c;那么必定会有优先级的问题。于是Spring就提供了Ordered这个接口&#xff0c;来处理相同接口实现类的优先级问题。 public class AuthorizeFilter implements Ordered, GlobalFilter {Overridepublic Mono<Void> filter(ServerW…

网络游戏租用价格表,一年、1个月收费明细表

游戏服务器租用多少钱一年&#xff1f;1个月游戏服务器费用多少&#xff1f;阿里云游戏服务器26元1个月、腾讯云游戏服务器32元&#xff0c;游戏服务器配置从4核16G、4核32G、8核32G、16核64G等配置可选&#xff0c;可以选择轻量应用服务器和云服务器&#xff0c;阿腾云atengyu…

springboot170图书电子商务网站的设计与实现

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的 适用于计算机类毕业设计&#xff0c;课程设计参考与学习用途。仅供学习参考&#xff0c; 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 获取资料方式 **项…

Android Studio无法安装Git问题解决(折中方案)

安装配置好studio&#xff0c;往往会使用git克隆github上面的项目&#xff0c;但是却发现git无法正确安装&#xff0c;本文将介绍如何解决git无法安装这一问题。 对于git安装&#xff0c;实际比较复杂&#xff0c;可以参考这一篇博客。 Git 详细安装教程&#xff08;详解 Gi…

jvm问题自查思路

本文聊一下最近处理了一些jvm的问题上&#xff0c;将这个排查和学习过程分享一下&#xff0c;看了很多资料&#xff0c;最终都会落地到几个工具的使用&#xff0c;本文主要是从文档学习、工具学习和第三方技术验证来打开认知和实践&#xff0c;希望有用。 一、文档 不仅知道了…