EcmaScript2015(ES6)中如何定義私有變量

自從世界從ES5轉到ES6,為了讓JavaScript代碼庫更加美觀,ES語法(不僅是語法)發生了巨大的變化。儘管其他所有語法都有所改進,但有一件令開發人員困擾的事情是,如何在類中聲明私有變量。但不幸的是,在ES6中沒有專門的語法。

沒有!ES6中沒有專門的語法來聲明私有變量。不過有一個提案。

新提案(還沒有實現)

class MyClass{
#private1;
#private2;
getPrivate1(){
return this.private1;
}
}

上面的語法是提交給TC39的一個提案,還沒被批准,並且在不久的將來肯定也不能用,但我們希望在未來的一些ES版本中可以有這種語法。

你可以創建模塊,而模塊中的所有東西都是私有的,直到以及除非你使用exports公開它。

let private1 = new WeakMap();
let private2 = new WeakMap();
class MyClass {
constructor() {
this.setPrivate1("something");
private2.set(this, "something else");
}
getPrivate1() {
return private1.get(this);//"something"
}
getPrivate2() {
return private2.get(this);//"something else"
}
setPrivate1(val) {
private1.set(this, val);
}
}
module.exports = MyClass;

為什麼不用let private1 = “something”; 這種方式

為什麼我們不聲明一個變量private1,然後將它所需的值賦給它呢?原因是,變量private1是一個會在MyClass的所有實例中共享的單一變量。所以只要有任何一個實例修改了private1,那麼同樣的變化就會反映到其它實例上。

為什麼是用WeakMap而不是Map?

Map和WeakMap之間的區別在於:對於WeakMap來說,如果鍵對象準備好被垃圾回收,就會自動刪除值;而對於Map來說,它會一直維持一個對鍵對象的引用,從而會導致內存洩漏。

還有其它幾種方式來聲明私有變量,每種方式各有其優缺點。其中的兩種方式描述如下。

命名約定

多年來人們一直在私有變量的名稱中使用下劃線。如果你根據這個約定,並且信任其他開發人員的話,就可以用這種方法。不過,這並不能確保數據的安全性,因為任何人如果想的話,他可以用或者甚至修改該數據。如果你正在開發一個庫,那麼這種方法強烈不推薦。


class MyClass {

constructor() {
this._private1 = "something";
this.public = "something else";
}
}

Object.assign

通過用Object.assign,你也能使用私有變量,並且能確保數據安全。但是這種方法的問題是,要讀寫該私有變量的方法不能是原型方法。這些方法與私有變量一起,也必須寫在構造器內。這不僅讓它對於其他開發人員來說很難去讀懂,而且也是一種低效率的聲明那個函數的方式;因為這些函數會被在該類的每個實例中重複(不是共享)。

class MyClass{
constructor(){
var private1 = "something";
Object.assign(this, {
getPrivate(){
return private1;
},
setPrivate(val){
private1 = val;
}
});
}
anotherMethod(){
console.log(private1); //ERROR
}
}

結論

有些人可能會推薦用ES6 Symbol來創建私有變量。幾個月前這種方式還是有效的,不過ES6已經修改了其草案,現在Symbol鍵從一個對象的外部也可以訪問了。所以遵循這種方式沒有意義。不過,最佳實踐是把你的程序分為模塊,並且用我展示的第一個方式來聲明私有變量。使用這種方式能確保數據安全,該類中所有方法將都能訪問該數據。我所看到的唯一缺點是,它給了你一種駭客式的感覺,因為與命名約定方式中相比,私有變量與類沒有太大關係。

EcmaScript2015(ES6)中如何定義私有變量


分享到:


相關文章: