iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 15
0
Modern Web

技術在走,Vue.js 要有系列 第 15

|D15| 從原始碼看 Vue 響應式原理 (1) - JS Object.defineProperty

平時物件賦值方式除了下面這樣外

let obj = {};
obj.name = 'mango';

還可以使用 Object 的靜態方法 Object.defineProperty,此方法會直接對一個物件定義、或是修改現有的屬性。執行後會回傳定義完的物件。如下

let obj={};
Object.defineProperty(obj,'name',{
    value:'mango'
});

console.log(obj)
// {name: "mango"}

Vue 就是透過 Object.defineProperty 做到雙向資料綁定來更新畫面。我們先看原生 JS Object.defineProperty 定義後再來實作簡單的雙向資料綁定。

語法

Object.defineProperty(obj, prop, descriptor)

傳入引數

  • obj: 目標物件
  • prop: 要定義的屬性或方法的名字
  • descriptor: 目標屬性所擁有的特性(descriptor)

物件內的屬性描述器(Property descriptor)主要有兩種

  • 資料描述器(data descriptor)
  • 訪問描述器(accessor descriptor)

資料描述器(data descriptor

資料描述器(data descriptor)是一個物件,可以選擇能否覆寫的屬性。擁有以下 key

  • configurable: 總開關,一但為 false,就不能再設定此物件的value、writable
  • enumerable: 是否能在 for…in 迴圈中遍歷出來或在Object.keys 中列舉出來
  • value: 定義了 value 後,不能再定義 get、set
  • writable: 如果為 false,屬性的值就不能被重寫,只能唯讀,默認值為 false。如果為 true,

訪問描述器(accessor descriptor)

訪問描述器(accessor descriptor)是一個物件,是由一對 getter、setter function 描述的屬性。擁有以下 key

  • configurable: 同上
  • enumerable: 同上
  • get: 讀取屬性時調用的 function,默認值為 underfined
  • set: 寫入屬性時調用的 function,默認值為 underfined

舉個例子

// 對 obj 定義訪問描述器 p
let obj = {};

Object.defineProperty(obj, 'p', {
  get: () => {
    return 1
  },
  set: (newValue) => {
    console.log(`只顯示不回傳,${newValue}`)
  }
})

// obj.p = 2 調用 set 方法,裡面只做了 console.log
obj.p = 2; // 只顯示不回傳,2

// console.log(obj.p) 調用 get 方法,裡面固定回傳 1
console.log(obj.p); // 1

簡單的 Vue 雙向綁定

HTML

<button id="btn-try">Try It</button>

// 視圖控制器
var viewBtn = {};

Object.defineProperty(viewBtn, "btnText", {
    get: function(){
        return document.getElementById('btn-try').innerHTML;
    },
    set: function(newText){
        document.getElementById('btn-try').innerHTML = newText;
    }
});

// 雙向綁定完成
viewBtn.btnText = 'xxxxx'

原本按鈕文字

雙向綁定完成


上一篇
|D14| 從原始碼看 Vue 元件化 (7) - 異步元件
下一篇
|D16| 從原始碼看 Vue 響應式原理 (2) MVVM
系列文
技術在走,Vue.js 要有30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言