關於簡單的數據雙向綁定原理,defineProperty 和Proxy演示

雙向綁定,也就是說js中的數據傳到頁面,頁面中的內容到js,實現同步更新,簡單的演示可以直接複製下放HTML程式碼運行。

在這個例子中,我們使用defineProperty ,Object.defineProperty() 方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性,並返回此對象。詳細資訊可以自行查看MDN文檔

簡單來說,defineProperty 就是一個監聽器,監聽對象中某一個屬性被訪問和修改,在Vue2.0中就是採用defineProperty 

注意事項

  1. 在使用get函數監聽屬性的時候,不能直接監聽當前屬性,否則會出現死循環。所以在使用前我將對象進行淺拷貝的原因
  2. 每一個defineProperty只能對一個對象屬性進行監聽,所以你必須在使用之前就得知道屬性的名字,但是很多時候屬性是動態生成的,,所以就很麻煩。
  3. <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    
    <body>
    
        <h1 id="hname"></h1>
        <input type="text" id="inputname">
    </body>
    
    <script>
        let stu = {
            name: ""
        }
        let newstu = { ...stu };//淺拷貝
        //監聽器
        Object.defineProperty(stu, "name", {
            get() {
                return newstu.name;
            },
            set(val) {
                if (val === newstu.name) return;
                newstu.name = val;
                doubleBind();
            }
        })
        //將數據傳到頁面中
        function doubleBind() {
            document.querySelector("#hname").innerHTML = stu.name;
            inputname.value = stu.name;//id可以直接使用
        }
        //輸入框事件,將頁面中數據返回
        inputname.oninput = function () {
            stu.name = inputname.value;
        }
        doubleBind()
        setTimeout(() => {
            stu.name = "Mary";
        }, 1000)
    </script>
    
    </html>

     

defineProperty的弊端很明顯,在ES6中提出了Proxy, 在Vue3.0中也將使用Proxy代替defineProperty,在Proxy中,我們可以在監聽整一個對象屬性的變化。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

    <h1 id="hname"></h1>
    <input type="text" id="inputname">
</body>

<script>
    let stu = {
        name: "12354"
    }
    
    //監聽器處理函數
   
    //監聽器
    stu = new Proxy(stu, {
        get(target, prop) {
          
            return target[prop];
        },
        set(target, prop,val){
            if (val === target.prop) return;
            target[prop] = val;
            doubleBind();
        }
    });
    //將數據傳到頁面中
    function doubleBind() {       
        document.querySelector("#hname").innerHTML = stu['name'];
        inputname.value = stu['name'];//id可以直接使用
    }
    //輸入框事件,將頁面中數據返回
    inputname.oninput = function () {
        stu['name'] = inputname.value;
    }
    doubleBind()
    setTimeout(() => {
        stu['name'] = "Mary";
        console.log(stu);
    }, 1000)
</script>

</html>

 

 

對比兩個例子,眼尖的friend會發現,第一個例子中我訪問對象屬性使用的是stu.name,而在第二個例子中使用的是stu[‘name’]的方式。在《javascript高級程式設計》

引用類型的那一章提到:一般來說,訪問對象屬性時使用的都是點表示法,這也是很多面向對象語言中通用的語法。不過,

在 JavaScript 也可以使用方括弧表示法來訪問對象的屬性。除非必須使用變數來訪問屬性,否則我們建議使用點表示法。在我們第二個例子Proxy中,prop是一個變數,所以我們使用方括弧。特別要注意,stu.namestu[name]是不一樣的,當然如果有外部變數name=「name「,就一樣了


Tags: