淺談在ES5環境下實現const


最近看到一個面試題——用ES5實現const。作為JS初學者的筆者知道在ES6中有const命令,可以用來聲明常量,一旦聲明,常量的值就不可改變。例如:

1
2
3
4
5
6
7
8
9
10
11
const Pi = 3.1415;
Pi
Pi = 3;
// TypeError: Assignment to constant variable.

const foo = {};
// 為 foo 添加一個屬性,可以成功
foo.prop = 123;
foo.prop // 123
// 將 foo 指向另一個對象,就會報錯
foo = {}; // TypeError: "foo" is read-only

但是讓我困惑的是,怎么才能使用ES5來實現const呢?說到這里我就想起了下半年···中美合拍···兩開花···啊不對!!是想起了最近在學習Vue框架,而Vue在實現響應式原理時使用到了Object.defineProperty()方法,該方法可以定義對象屬性的數據描述符,比如configurable、writable、enumerable等等,通過這些描述符就可以設置對象屬性是否可讀可寫可配置可枚舉,進而就可以實現類似定義常量的功能。

Object.defineProperty() 方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性, 並返回這個對象。語法如下:

Object.defineProperty(obj, prop, descriptor)

其中descriptor代表將被定義或修改的屬性描述符。屬性描述符有兩種主要形式:數據描述符存取描述符。本文只討論數據描述符,數據描述符有以下選項:

  • configurable

    當且僅當該屬性的 configurable 為 true 時,該屬性描述符才能夠被改變,同時該屬性也能從對應的對象上被刪除。默認為 false

  • enumerable

    當且僅當該屬性的enumerabletrue時,該屬性才能夠出現在對象的枚舉屬性中。默認為 false

  • value

    該屬性對應的值。可以是任何有效的 JavaScript 值(數值,對象,函數等)。默認為 undefined

  • writable

    當且僅當該屬性的writabletrue時,value才能被賦值運算符改變。默認為 false

此時我們設想,當我們講對象屬性中的writable設為false的時候,該屬性是只讀的,就能滿足我們對常量的要求了。

1
2
3
4
5
6
7
8
9
var _const = {};
Object.defineProperty(_const, "A", {
value: 1,
writable: false, //設置屬性只讀
configurable: true,
enumerable: true
});
console.log(_const.A); //1
_const.A = 2; //在嚴格模式下會拋錯,在非嚴格模式下靜默失敗,修改無效。

但此時,我們只要修改屬性的數據描述符來修改屬性值,依然可以對屬性值進行修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var _const = {};
Object.defineProperty(_const, "A", {
value: 1,
writable: false,
configurable: true,
enumerable: true
});

Object.defineProperty(_const, "A", {
value: 2,
writable: true,
configurable: true,
enumerable: true
});
console.log(_const.A); < 大專欄  淺談在ES5環境下實現constspan class="comment">//2
_const.A = 3;
console.log(_const.A); //3

如此我們就需要將configurable設置為false,這樣屬性就不可配置了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var _const = {};
Object.defineProperty(_const, "A", {
value: 1,
writable: false,
configurable: false,
enumerable: true
});
console.log(_const.A) //1
_const.A = 2; //Cannot redefine property: A
Object.defineProperty(_const, "A", {
value: 2,
writable: true,
configurable: true,
enumerable: true
}); //報錯!屬性不可配置

但是configurable特性表示對象的屬性是否可以被刪除,以及除writable特性外的其他特性是否可以被修改。所以writable特性依舊可以修改,僅限於由true改為false,不能由false改為true。並且value值的設置也不會應此受到影響,則會出現下述情況:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var _const = {};
Object.defineProperty(_const, "A", {
value: 1,
writable: true,
configurable: false,
enumerable: true
});
console.log(_const.A); //1
Object.defineProperty(_const, "A", {
value: 2, //該屬性不受configurable的影響
writable: false,
configurable: false,
enumerable: true
});
console.log(_const.A); //2
_const.A = 3;
console.log(_const.A); //2 修改無效

因此,通過Object.defineProperty() 方法,使用屬性的數據描述符,可以定義一個命名空間,將常量封裝在命名空間里面。由於屬性描述符默認為false,所以可以這樣定義:

1
2
3
4
5
6
7
8
9
var _const = {};
Object.defineProperty(_const, "A", {
value: 1,
enumerable: true
});
Object.defineProperty(_const, "B", {
value: 2,
enumerable: true
});

參考鏈接:

1.JavaScript 常量定義

2.Object.defineProperty()

3.ECMAScript 6 入門-阮一峰


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM