相關文章:【阿里面試】有關symbol的一些知識(1)-基礎知識
【阿里面試】有關symbol的一些知識(2)-實例
【阿里面試】有關symbol的一些知識(3)-內置方法
實例:消除魔術字符串
魔術字符串指的是,在代碼之中多次出現、與代碼形成強耦合的某一個具體的字符串或者數值。風格良好的代碼,應該儘量消除魔術字符串,改由含義清晰的變量代替。
function getArea(shape, options) {
let area = 0;
switch (shape) {
// 字符串Triangle就是一個魔術字符串。
// 它多次出現,與代碼形成“強耦合”,不利於將來的修改和維護。
case "Triangle":
area = 0.5 * options.width * options.height;
break;
/* ... more code ... */
}
return area;
}
getArea("Triangle", { width: 100, height: 100 }); // 魔術字符串
常用的消除魔術字符串的方法,就是把它寫成一個變量。
// 把Triangle寫成shapeType對象的triangle屬性,這樣就消除了強耦合。
const shapeType = {
triangle: "Triangle",
};
function getArea(shape, options) {
let area = 0;
switch (shape) {
case shapeType.triangle:
area = 0.5 * options.width * options.height;
break;
}
return area;
}
getArea(shapeType.triangle, { width: 100, height: 100 });
如果仔細分析,可以發現 shapeType.triangle
等於哪個值並不重要,只要確保不會跟其他 shapeType
屬性的值衝突即可。因此,這裏就很適合改用 Symbol
值。
const shapeType = {
triangle: Symbol(),
};
實例:模塊的 Singleton 模式
Singleton 模式指的是調用一個類,任何時候返回的都是同一個實例。
對於 Node 來說,模塊文件可以看成是一個類。怎麼保證每次執行這個模塊文件,返回的都是同一個實例呢?
很容易想到,可以把實例放到頂層對象 global
。
// mod.js
function A() {
this.foo = "hello";
}
if (!global._foo) {
global._foo = new A();
}
module.exports = global._foo;
// 變量a任何時候加載的都是A的同一個實例。
const a = require("./mod.js");
console.log(a.foo);
但是,這裏有一個問題,全局變量 global._foo
是可寫的,任何文件都可以修改。
// 會使得加載mod.js的腳本都失真
global._foo = { foo: "world" };
const a = require("./mod.js");
console.log(a.foo);
爲了防止這種情況出現,我們就可以使用 Symbol
。
// mod.js
const FOO_KEY = Symbol.for("foo");
function A() {
this.foo = "hello";
}
if (!global[FOO_KEY]) {
global[FOO_KEY] = new A();
}
module.exports = global[FOO_KEY];
上面代碼中,可以保證 global[FOO_KEY]
不會被無意間覆蓋,但還是可以被改寫。
global[Symbol.for("foo")] = { foo: "world" };
const a = require("./mod.js");
如果鍵名使用 Symbol
方法生成,那麼外部將無法引用這個值,當然也就無法改寫。
// mod.js
const FOO_KEY = Symbol("foo");
// 後面代碼相同 ……
上面代碼將導致其他腳本都無法引用 FOO_KEY
。但這樣也有一個問題,就是如果多次執行這個腳本,每次得到的 FOO_KEY
都是不一樣的。雖然 Node 會將腳本的執行結果緩存,一般情況下,不會多次執行同一個腳本,但是用戶可以手動清除緩存,所以也不是絕對可靠。
原文:# ECMAScript 6 入門