JavaScript从某些角度来看是一门残缺的语言,即使es6在语法层面上实现了类和继承,但也只不过是语法糖而已,而且还没有实现私有成员。
当然,JavaScript没有什么不能靠hack来实现的,下面介(摘)绍(抄)一下几种模拟出私有成员的方法。
基于约定
如果使用ES6,约定以下划线_
开头的成员名作为私有成员。
class Animal {
constructor() {
this._notPublicProperty = 2
}
_notPublicMethod () {
return this._notPublicProperty
}
}
这样貌似也勉强够用,但是只能靠使用者的自觉,遵守命名规则。
ES5基于闭包
function Animal() {
}
Animal.prototype = (function () {
var self = this;
var _notPublicProperty = 2;
function _notPublicMethod() {
return _notPublicProperty;
}
return {
constructor: Animal,
getNotPublicProperty: function() {
return _notPublicMethod.call(this)
}
}
}())
var dog = new Animal()
console.log(dog.getNotPublicProperty()); // 2
console.log(dog._notPublicMethod()); // ReferenceError: _notPublicProperty is not defined
Symbol
复习一下JavaScript的六种基本数据类型
undefined null number string object boolean
ES6为JavaScript引入了一种新的基本数据类型 -- Symbol
。
Symbol是一个全局函数,每调用一次就会产生一个唯一的字符串,关于Symbol的详细介绍可以参见 阮一峰的ES6教程
const _notPublicMethod = Symbol()
const _notPublicProperty = Symbol()
class Animal {
constructor() {
this[_notPublicProperty] = 2;
}
[_notPublicMethod]() {
return this[_notPublicProperty]; // 必须用中括号
}
getNotPublicProperty() {
return this[_notPublicMethod]()
}
}
var dog = new Animal()
console.log(dog.getNotPublicProperty()); // 2
console.log(dog._notPublicMethod()); // ReferenceError: _notPublicProperty is not defined
每次都要创建一个Symbol还是不那么完美,但是已经不错了。
WeakMap
Map和WeakMap都是ES6新引入的数据结构。
Map和Object类似,都是hash结构。Object的键只能是字符串,而Map打破了这一限制,键可以是任意数据类型,而WeakMap比Map要弱一点,键只能是对象;且WeakMap的键名所指向的对象,不计入垃圾回收机制。
主要的思路是,在类的级别上创建一个 WeakMap 容器,用于存储各个实例的私有成员
const store = new WeakMap()
class Animal {
constructor() {
var self = this;
function _notPublicMethod() {
return store.get(this)._notPublicProperty
}
store.set(this,{
_notPublicProperty: 2,
_notPublicMethod: _notPublicMethod.bind(self)
})
}
getNotPublicProperty() {
return store.get(this)._notPublicMethod
}
}
var dog = new Animal()
console.log(dog.getNotPublicProperty()); // 2
console.log(dog._notPublicMethod()); // ReferenceError: _notPublicProperty is not defined
貌似引入WeakMap使得问题更加复杂,还是我的打开方式不对?
最后,还是希望babel和node能够尽快支持最新的提案,使用#
来自然的标识私有成员,写hack真的很hack啊!