1

defineProperty

Object提供的方法,用于给对象添加自定义属性具体用法如下:

const obj = { _value: 1 };

Object.defineProperty(obj, 'value', {
    get: function() {
        console.log('get方法执行');
        return this._value;
    },
    set: function(a) {
        console.log('set方法执行');
        this._value = a;
    }
})
obj.value = 3;
console.log(obj.value);
console.log(obj._value);

在node中执行结果如下:

image.png

下面来分析一下代码
首先定一个对象,并对对象添加一个自定义属性value,同时添加了getter,setter两个函数用来分别控制value属性的修改和获取,
当执行obj.value = 3;时,会自动调属性的setter方法,将value的修改同步到_value属性上,当执行obj.value语句获取属性值时,会自动调用getter方法获取方法的返回值;

总结(参考MDN)
该方法接收三个参数
obj:要添加属性的对象
prop: 要定义的属性
descriptor:要定义或者修改的属性描述符
其中描述符包含以下几种

  1. configurable:布尔值,控制属性是否能改变(除了value,writable)及删除
  2. enumerable: 布尔值,控制属性是否可枚举,即通过for in循环或者Object.keys访问
  3. value:属性值,可以时任何有效JavaScript值
  4. writable 布尔值,属性可否通过赋值修改
  5. get:属性getter函数,执行时传入this,this值取决于调用者
  6. set:属性setter函数,赋值时执行,并传入this

双向绑定

由此可以设计一下数据双向绑定的简单实现:
在数据对象内定义属性,通过对dom绑定事件监听dom内值的变化,并赋值给数据对象,数据对象的改动会调用自身的setter方法,在方法内在动态修改dom内容。

代码如下:

<!-- 简单数据双向绑定实现 -->
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <div id="root">
            <button id='btn'>请求数据</button>
        </div>
    </body>
    <script>
        const root = document.getElementById('root');
        const btn = document.getElementById('btn');
        const input = document.createElement('input');
        const model = document.createElement('p');
        const dataModel = {
            _value:0,
        }
        Object.defineProperty(dataModel, 'value', {
            configurable: true,
            set:function(value){
                this._value = value;
                input.value = value;
                model.innerHTML = `<span>数据模型:</sapn> ${value}`;
            },
            get:function(){
                return this._value;
            }
        })

        btn.addEventListener('click', () => {
            const range = Math.floor(Math.random(0, 1) * 100);
            dataModel.value = range;
        })

        input.addEventListener('input',(ev) => {
            dataModel.value = ev.target.value;
        })

        const initPage = () => {
            dataModel.value = 100;
        }
        initPage();
        root.append(input);
        root.append(model);
    </script>
</html>

描述有点乱,看实现代码更清晰一点,有问题欢迎指正


张磊
15 声望1 粉丝