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)中如何定义私有变量


分享到:


相關文章: