玩转ES6(二)-Object.defineProperty和Proxy代理

Object.defineProperty

Object.defineProperty这个并不是es6的语法,这个是给一个对象,添加属性,但是目前框架很多实用这个方法,来实现数据劫持,也就是数据双向绑定

// 平时我们这样给一个对象添加属性	
let obj = {str:"hello swr"}	
obj.str = 'goodbye swr'	
console.log(obj.str) // 'goodbye swr'

那么当我们想在给一个对象,读取值或写入值时,进行别的操作,该怎么做呢?

// 使用Object.defineProperty()	
// 接收的第一个参数为对象,第二个参数为属性名,第三个参数为配置对象	
let obj = {}	
Object.defineProperty(obj,'name',{	
    enumerable:true,// 是否可枚举,默认值 true	
                    // 如果为false的话,打印这个obj对象,是看不到name这个属性	
    writable:true,  // 是否可写,默认值 true	
                    // 如果为false的话,给name赋值,不会生效	
    configurable:true, // 是否可配置(是否可删除),默认值 true	
                       // 如果为true,delete obj.name,再打印obj,则显示{}	
                       // 如果为false,delete obj.name,再打印obj,则显示{name:undefined}	
   value:'swr', // name对应的值	
})	
	
// 上面的写法其实和下面的写法是一样的	
let obj = {}	
obj.name = 'swr'

那么既然一样,我们有必要写这么大串的代码吗?

其实核心是get和set,我们继续往下看

// 需要注意的是,当使用get set时,则不能使用value和writable	
let obj = {}	
let str	
Object.defineProperty(obj,'name',{	
    enumerable:true,	
    configurable:true, 	
    get(){ // 读,当我们读取时,则会执行到get,比如obj.name	
        // return 'swr' // 当我们obj.name进行读取时,会返回'swr'	
        return str	
    },	
    set(newValue){ // 写,当我们写入时,则会执行到set,比如obj.name = 'swr'	
                   // 并且会把newValue作为参数传进去	
        str = newValue	
    }	
})	
	
obj.name = 'swr' // 写入	
console.log(obj.name) // 'swr'  // 读取

这样一来,我们可以在get set函数中,写出对应的业务逻辑,

包括很多框架底层,例如

// 一般不再选择这样的写法	
Fn.prototype.xxx = xxx	
	
// 更多的是选择这样的写法	
// 这样的好处就是当读取值的时候,可以做一系列我们想做的事情	
Object.defineProperty(Fn.prototype,'xxx',{...})

那么我们实现数据双向绑定呢?

这个问题在面试当中,会经常问这个问题,但是面试官更希望听到的是具体底层的实现方式,那么接下来我们也实现一下吧~ ( 简陋版的……(#^.^#)

<!DOCTYPE html>	
<html lang="en">	
<head>	
  <meta charset="UTF-8">	
  <meta name="viewport" content="width=device-width, initial-scale=1.0">	
  <meta http-equiv="X-UA-Compatible" content="ie=edge">	
  <title>对象的数据双向绑定</title>	
</head>	
	
<body>	
  <input id='input' type="" name="" value="">	
  <script>	
    let el = document.getElementById('input') // 1. 获取输入框的dom节点	
    let obj = { // 2. 创建一个对象	
      name: ""	
    }	
	
    function oberseve(obj) { // 3. 对对象进行观察	
      if (typeof obj !== 'object') return // 3.1 判断参数是否为对象	
      for (let key in obj) { // 3.2 对对象进行遍历,目的是为了把每个属性都设置get/set	
        defineReactive(obj, key, obj[key])	
        oberseve(obj[key]) // 3.3 obj[key] 有可能还是一个函数,需要递归,给obj[key]里的属性进行设置get/set	
      }	
    }	
	
    function defineReactive(target, property, value) { // 4. 使用Object.defineProperty	
      Object.defineProperty(target, property, {	
        get() {	
          el.value = value // 4.1 当读取时,把值赋值给input框	
          return value	
        },	
        set(newVal) {	
          el.value = newVal // 4.1 当设置时,把赋值给input框	
          value = newVal	
        }	
      })	
    }	
	
    oberseve(obj) // 5.执行该函数,对obj对象里的属性进行设置get/set	
    el.addEventListener('input', function () { // 6.给输入框绑定input事件	
      obj.name = this.value // 7.当输入框输入内容时,我们会把输入框的	
                            //   内容赋值给obj.name,触发obj.name的set方法	
    })	
  </script>	
</body>	
</html>

当我们在输入框输入内容时,再到控制台输入obj.name查看这个值时,会发现打印出"hello swr"

640?wx_fmt=png

当我们在控制台,给obj.name赋值时,会发现输入框的内容也会作出相应更改

640?wx_fmt=png

这样我们就实现了一个简陋版的数据双向绑定了,但是这也是有缺点的,这个只是针对对象进行了数据双向绑定,而尤大大的Vuejs就是基于Object.defineProperty实现的。

除了Object.defineProperty可以实现数据双向绑定之外,还有其他方式吗?

肯定是有其他方式可以实现的,利用es6的proxy代理也可以实现数据双向绑定,但是目前的框架还是比较少使用这种方式。


Proxy

Proxy代理也可以进行数据劫持,但是和Object.defineProperty不同的是,Proxy是在数据外层套了个壳,然后通过这层壳访问内部的数据,目前Proxy支持13种方式。

640?wx_fmt=png

Proxy,我的理解是在数据外层套了个壳,然后通过这层壳访问内部的数据,就像下面的图

640?wx_fmt=png

let dog = {	
  name:"小黄",	
  firends:[{	
    name:"小红"	
  }]	
}	
	
// 1.首先new一个Proxy对象	
let proxy = new Proxy(dog,{ // 2.参数一为需要代理的数据,参数二为上图可以代理的13种的配置对象	
    get(target,property){ // 3.参数1为上面dog对象,参数2为dog的属性	
        console.log('get被监控到了')	
        return target[property]	
    },	
    set(target,property,value){ // 4.参数1为上面dog对象,参数2为dog的属性,参数3为设置的新值	
                                // 有点类似Object.defineProperty	
        console.log('set被监控到了')	
        target[property] = value	
    }	
})	
	
// 那么接下来我们设置一下这个属性	
// dog.name = '小红'  // set值时,发现不会打印 'set被监控到了'	
// dog.name // get值时,发现不会打印 'get被监控到了'	
	
// 思考:为什么在set/get值的时候不会打印出来我们需要的东西呢?	
	
// 上面说得很明白了,proxy相当于是一个壳,代理我们需要监控的数据,也就是我们要通过proxy来访问内部数据才会被监控到	
	
proxy.name = '小红' // 打印输出 'set被监控到了'	
proxy.name // 打印输出 'get被监控到了'
// Reflect经常和Proxy搭配使用	
// 比如我们上面的例子中	
let proxy = new Proxy(dog,{ 	
    get(target,property){ 	
        console.log('get被监控到了')	
        return target[property]	
    },	
    set(target,property,value){ 	
        console.log('set被监控到了')	
        // target[property] = value 	
        // 这里的target[property] = value 可以用下面的写法	
        Reflect.set(target,property,value)	
    }	
})
// 那么我们该怎样实现深度的数据劫持呢?	
let dog = {	
  name:"小黄",	
  firend:{	
    name:"小红"	
  }	
}	
	
// 我们首先写一个set方法,希望是通过这样来调用	
set(dog.firend,funtion(obj){	
    console.log(obj) // { name:"小红" }  回调函数中的obj代表的是dog.firend的对象	
})
// 实现	
let dog = {	
  name:"小黄",	
  firend:{	
    name:"小红"	
  }	
}	
	
function set(obj,callback){	
    let proxy = new Proxy(obj,{	
        set(target,property,value){	
            target[property] = value	
        }	
    })	
    // 最后把proxy传给我们的回调函数	
    callback(proxy)	
}	
	
set(dog.firend,function(obj){	
    console.log(obj) // { name:"小红" } 实际就是从set函数中传出来的proxy对象	
})

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值