はじめに
#
を付ける方法は、対応ブラウザが少ないため、#
を使用せずにprivateを実現する方法として、こちらの記事を参考にさせて頂きました。
JavaScriptでprivate「Symbol」編
問題点
- クラスを定義する前にprivateなプロパティ名を列挙しなければならない
- publicとprivateで書き方がだいぶ違う
- クラス作るたびにアロー関数作ってシンボル作ってとやることが多い
- 完全なprivateじゃない
上記の記事では、これらの問題点が挙げられていました。
解決策
これらの問題点は「完全なprivateじゃない」を除き
- Symbolの保持
- 保持したSymbolの参照
これらの書き方が異なることに起因しています。
つまり、これらの書き方を1つに統一することが出来れば、問題は解決すると言えます。
「完全なprivateじゃない」については
delete Object.getOwnPropertySymbols
このように記述しておくことで、Hard privateを実現出来なくは無いので特に問題はありません。
シンプルなSymbol処理
const PrivateModifier = function() {
return new Proxy({}, {
get(obj, name) {
if (obj[name] === undefined) {
obj[name] = Symbol(name)
}
return obj[name]
},
set() {
throw TypeError("PrivateModifier is read only.")
}
})
}
解説
通常、objectは存在しないプロパティにアクセスした場合、undefinedを返します。
Proxyを利用することで、デフォルトの挙動を変更出来ます。
PrivateModifier
は、存在しないプロパティにアクセスした際、Symbolを動的に設定するobjectを作成します。
例えば
const _ = {}
_.hoge = Symbol("hoge")
console.log(_.hoge) // Symbol(hoge)
_.huga = Symbol("huga")
console.log(_.huga) // Symbol(huga)
const _ = new PrivateModifier
console.log(_.hoge) // Symbol(hoge)
console.log(_.huga) // Symbol(huga)
これらは同じ意味になります。
値はこのようになります。
const _ = new PrivateModifier
console.log(_.hoge === _.hoge) // true
使用方法
パターン1 (prototype)
const ClassName = (function() {
const _ = new PrivateModifier
// constructor
function ClassName(privateValue, publicValue) {
// private instance
this[_.privatePropertyName] = privateValue
// public instance
this.publicPropertyName = publicValue
}
// alias
const proto = ClassName.prototype
// private prototype
proto[_.privateMethodName] = function() { }
// public prototype
proto.publicMethodName = function() { }
return ClassName
})()
パターン2 (class)
const ClassName = (() => {
const _ = new PrivateModifier
return class ClassName {
constructor(privateValue, publicValue) {
// private instance
this[_.privatePropertyName] = privateValue
// public instance
this.publicPropertyName = publicValue
}
// private prototype
;[_.privateMethodName]() { }
// public prototype
publicMethodName() { }
}
})()
対応状況
- IE以外のブラウザで使用できます