javascript用defineProperty實現簡單的雙向綁定

defineProperty

Object提供的方法,用於給對象添加自定義屬性具體用法以下:html

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中執行結果以下:node

image.png

下面來分析一下代碼
首先定一個對象,並對對象添加一個自定義屬性value,同時添加了getter,setter兩個函數用來分別控制value屬性的修改和獲取,
當執行obj.value = 3;時,會自動調屬性的setter方法,將value的修改同步到_value屬性上,當執行obj.value語句獲取屬性值時,會自動調用getter方法獲取方法的返回值;app

總結(參考MDN)
該方法接收三個參數
obj:要添加屬性的對象
prop: 要定義的屬性
descriptor:要定義或者修改的屬性描述符
其中描述符包含如下幾種dom

  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內容。函數

代碼以下:this

<!-- 簡單數據雙向綁定實現 -->
<!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>

描述有點亂,看實現代碼更清晰一點,有問題歡迎指正spa

相關文章
相關標籤/搜索