ES5 中模擬 ES6 的 Symbol 實現私有成員

ES6 中有類語法,定義類變得簡單了javascript

class Person {
    constructor(name) {
        this._name = name;
    }
    
    get name() {
        return this._name;
    }
}

然而,並無提供私有屬性。好比上面的 Person 實際上是但願在構造的時候傳入 name,以後不容許修改了。不過,因爲沒有私有屬性,因此不免有人會這樣幹:java

Person james = new Person("James");
james._name = "Tom";        // God Save Me

不過,若是想定義私有成員,也有變通的方式,好比廣爲留傳的 Symbol 大法dom

var Person = (function() {
    let _name = Symbol();
    class Person {
        constructor(name) {
            this[_name] = name;
        }
        
        get name() {
            return this[_name];
        }
    }
    return Person;
})();

其實質在於匿名函數中的 Symbol 實例 _name 是局部變量,在外部不可訪問。而 Symbol 因爲自身的惟一性特色,也無法再造一個相同的出來,因此就模擬出來一個私有成員了。函數

按照此思路,在 ES5 中其實也很容易模擬私有成員。局部變量是很容易作到的,在函數範圍內 letvar 是同樣的效果。問題在於模擬 Symbol 的惟一性。this

ES5 沒有 Sybmol,屬性名稱只多是一個字符串,若是咱們能作到這個字符串不可預料,那麼就基本達到目標。要達到不可預期,一個隨機數基本上就解決了。prototype

var Person = (function() {
    var _name = "00" + Math.random();
    function Person(name) {
        this[_name] = name;
    }
    
    Object.defineProperty(Person.prototype, "name", {
        get: function() {
            return this[_name];
        }
    });

    return Person;
})();

若是這個程序在 Web 頁面中加載,那麼每次刷新頁面 _name 的值都會不一樣,但並不會影響程序的邏輯,外部程序不會出現任何不適。調試

然而與 Symbol 方案相比,它的問題在於這個 _name 的值不會像 Symbol 同樣會隱藏起來,在控制檯能夠用不少種辦法把它找出來——固然在調試階段這樣作也沒什麼不能夠。在開發階段這個值仍然是不可預料的。code

對於單個私有屬性的狀況,有人會找到私有 Key 的規律,好比上面的私有 Key 就是以 "000." 開始的,遍歷對象屬性很容易找出來。在多個私有 Key 的狀況下,也能夠經過一些技術手段來找,好比對象

function getPersonNameKey() {
    var v = "" + Math.random();
    var p = new Person(v);
    for (var k in p) {
        if (p[k] === v) {
            return k;
        }
    }
}

但這些都是後話,作起來太費勁,通常人不會這麼幹。況且 Symbol 也是能夠遍歷的(經過 Object.getOwnPropertySymbols()),徹底能夠以一樣的方法來獲取私有 Key。ip

綜上,ES5 中模擬 Symbol 來實現私有屬性的目的已經達到了。

相關文章
相關標籤/搜索