JS33 监听对象 Object.defineProperty 数据代理 vue中数据代理原理

文章详细介绍了JavaScript的Object.defineProperty方法,用于监听并响应对象属性的变化,从而实现数据绑定。通过示例展示了如何使用该方法定义getter和setter,以及属性描述符的configurable、writable、enumerable等关键属性。同时,文章还讨论了Vue框架中的数据代理机制,解释了Vue如何通过Object.defineProperty实现数据绑定,提高数据操作的便利性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Object.defineProperty详细介绍使用方法
Object.defineProperty方法
描述
请补全JavaScript代码,要求如下:

  1. 监听对象属性的变化
  2. 当"person"对象的属性发生变化时,页面中与该属性相关的数据同步更新
    注意:
  3. 必须使用Object.defineProperty实现且触发set方法时更新视图
  4. 可以使用预设代码"_render"函数
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
        <style>
            ul {
                list-style: none;
            }
        </style>
        <ul></ul>

        <script>
            var ul = document.querySelector('ul');
            var person = { sex: '男', age: '25', name: '王大锤', height: 28, weight: 32 };
            const _render = element => {
                var str = `<li>姓名:<span>${person.name}</span></li>
                           <li>性别:<span>${person.sex}</span></li>
                           <li>年龄:<span>${person.age}</span></li>
                           <li>身高:<span>${person.height}</span></li>
                           <li>体重:<span>${person.weight}</span></li>`
                element.innerHTML = str;
            }
            _render(ul);
           //重新渲染视图
           //因为Object.defineProperty 监听一个属性 所以遍历对象中的属性
           const observer =(target)=>{
                if(typeof target!=='object'||target==null){
                    return target
                }
                for(let key in target){
                    definedReact(target,key,target[key]);
                }
           }

           function definedReact(target,key,value){
                Object.defineProperty(target,key,{
                    get:function(){
                        return value;
                    },
                    set:function(newValue){
                        if(value!==newValue){
                            value=newValue
                            _render(ul)
                        }
                    }
                })
           }
        observer(person)
        </script>
    </body>
</html>

这里只简要介绍一下,Object.defineProperty也是vue数据双向绑定原理,关于其参数,监听对象,属性,这里面还有方法对象。当数据改变时,可以使用set方法来改变。

属性详解:

Object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象上的现有属性,并返回这个对象。
1.obj: 要在其定义上的对象。
2.prop:要定义或者修改的属性的名称。
3.descriptor:将被定义或者修改的属性描述符

属性描述符是一个javaScript对象,包含如下属性:

1.configurable:当属性为configurable为true时,该描述符才能够被改变也能被删除。false时不能删除。

 <script>
    var obj = {
      theme: "test",
    };
    Object.defineProperty(obj, "propertyName", {
      value: "Hello World",
      configurable: false,
    });
  </script>

在window属性中可以看到
在这里插入图片描述
由于删除属性configurable为false,所以不能删除。
在这里插入图片描述
2.value:该属性对应的值。可能是任何有效的 JavaScript 值(数值,对象,函数等)。

  <script>
    var obj = {
      theme: "test",
      propertyName: "Hello World",
    };
    Object.defineProperty(obj, "propertyName", {
      configurable: true,
      get(){
        return "newValue"
      }
    });
  </script>

在这里插入图片描述
3.enumerable:当且仅当该属性的 enumerable 为 true 时,该属性才能够出现在对象的枚举属性中。

  <script>
    var obj = {
      theme: "test",
      propertyName: "Hello World",
    };
    Object.defineProperty(obj, "propertyName", {
      enumerable:false,
      get(){
        return "newValue"
      }
    });
    console.log(Object.keys(obj));
  </script>

在这里插入图片描述

4.writable:当且仅当该属性的 writable 为 true 时,该属性才能被赋值运算符改变。如果为false则会修改不了

    var obj = {
      theme: "test",
      propertyName:"hello world"
    };
    Object.defineProperty(obj, "propertyName", {
      writable:false,
    });

在这里插入图片描述
使得属性被设置为了不可写,theme是对象中原有的属性,可以修改。但是现在设置的propertyName不可修改,所以就算修改数据中还是未改变。
Object.defineProperty详细介绍使用方法

数据代理:
通过一个对象代理对另外一个对象中属性的操作(读/写)

let obj = {
    x: 100
}

let obj2 = {
    y: 200
}

此时可以直接访问obj中的x和直接访问obj2中的y
在这里插入图片描述

如果:此时想要访问objx的值,但是不希望直接通过obj,而是通过obj2这个代理去访问。
这是需要Object.defineProperty(),给obj2添加上访问器属性

let obj = {
    x: 100
}

let obj2 = {
    y: 200
}

Object.defineProperty(obj2, 'x', {
    get() {
        return obj.x;
    },
    set(value) {
        obj.x = value;
    }
})

通过obj2查看obj1的数据
在这里插入图片描述
通过obj2去修改obj1中x的数据:可以观察到obj的中的x数据已经被修改。
在这里插入图片描述

vue中数据代理原理
vue中数据代理:通过vm对象来代理data对象中属性的操作(读/写)
vue中数据代理的好处:更加方便的操作data中数据
基本原理:
通过object.defineProperty()把data对象中所有属性添加到vm上。
为每一个添加到vm上的属性,指定一个getter、setter
在getter、setter内部去操作data中对应的属性。

<body>
    <div id="root">
        <h2>名称:{{name}}</h2>
        <h2>地址:{{address}}</h2>
    </div>
    
    <script>
        const vm = new Vue({
            el: '#root',
            data: {
                name: 'weixi',
                address: '雅安'
            }
        })
        console.log(vm)
    </script>
</body>

在这里插入图片描述
写在配置项中的data数据被绑定在vm对象上,原因是因为vue将_data中的name,address数据代理到vm本身上。
_data是vm身上的属性如下图:
在这里插入图片描述
而_data是从哪里来的?

 const vm = new Vue({
            el: '#root',
            data: {
                name: 'weixi',
                address: '雅安'
            }
        })

在new vue时,vue通过一系列处理,将匹配的data数据绑定到_data这个属性上,对这个属性进行了处理,(数据劫持)
将vm_data中的值再代理到vm本身来,用vm.name代替vm.data.name。就是vue的数据代理。
在这里插入图片描述
原因是通过Object.defineProperty()完成的

Object.defineProperty(vm, 'name', {
    get() {
        return vm._data.name;
    },
    set(value) {
        vm._data.name = value
    }
})

这样做的意义?可以直接通过vm._data.name访问name的值,为啥通过这样操作?
在插值语法中,{{name}}取值相当于{{vm.name}},不用数据代理插值表达式需要{{_data.name}}

内容是在b站张天禹老师所讲总结。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值