如何在 ES5 環境下實現一個const ?

陳大魚頭發表於2018-12-24

我的GitHub地址:Github

前言

  • 剛剛看了掘金上一篇文章《作為技術面試官,為什麼把你pass了》,裡面第一題就是用es5實現const,據作者反饋 這一題所有的面試者都沒有回答出來,感覺挺可惜的,其實這是一道比較簡單的題目,但是由於涉及到了一些Object物件屬性描述符的知識,這些描述符往往用到的場景不多,所以不容易記住。

屬性描述符:

物件裡目前的屬性描述符有兩種:

  • 資料描述符:具有值的屬性
  • 存取描述符:由getter與setter函式對描述的屬性

描述符功能:

資料描述符與存取描述符皆可修改:

  • configurable:當前物件元素的屬性描述符是否可改,是否可刪除
  • enumerable:當前物件元素是否可列舉

唯有資料描述符可以修改:

  • value: 當前物件元素的值
  • writable:當前物件元素的值是否可修改

唯有存取描述符可以修改:

  • get:讀取元素屬性值時的操作
  • set:修改元素屬性值時的操作

描述符可同時具有的鍵值:

configurable enumerable value writable get set
資料描述符 Yes Yes Yes Yes No No
存取描述符 Yes Yes No No Yes Yes

const 實現原理

由於ES5環境沒有block的概念,所以是無法百分百實現const,只能是掛載到某個物件下,要麼是全域性的window,要麼就是自定義一個object來當容器

      var __const = function __const (data, value) { 
window.data = value // 把要定義的data掛載到window下,並賦值value Object.defineProperty(window, data, {
// 利用Object.defineProperty的能力劫持當前物件,並修改其屬性描述符 enumerable: false, configurable: false, get: function () {
return value
}, set: function (data) {
if (data !== value) {
// 當要對當前屬性進行賦值時,則丟擲錯誤! throw new TypeError('Assignment to constant variable.')
} else {
return value
}
}
})
} __const('a', 10) console.log(a) delete a console.log(a) for (let item in window) {
// 因為const定義的屬性在global下也是不存在的,所以用到了enumerable: false來模擬這一功能 if (item === 'a') {
// 因為不可列舉,所以不執行 console.log(window[item])
}
} a = 20 // 報錯複製程式碼

題外話

Vue目前雙向繫結的核心實現思路就是利用Object.defineProperty對getset進行劫持,監聽使用者對屬性進行呼叫以及賦值時的具體情況,從而實現的雙向繫結~~

來源:https://juejin.im/post/5c2042e95188255e9b620964

相關文章