你們都知道JavaScript不像Java這類強類型語言,有特定的字面量(private)來定義參數爲類的私有參數;那JavaScript如何能實現私有變量呢,下面來介紹幾種實現方式。閉包
var PClass = (function(){
var a = '私有變量';
var getA = function(){
console.log(a, '私有方法')
}
var setA = function(val){
a = val
}
function P (){
this.b = '變量b,外部可訪問'
}
P.prototype = {
getB : function(){
console.log(this.b,'--- 獲取對象公有屬性b ---')
},
setType: function(a,val){
if(a == 'a'){
setA(val);
}
},
getType: function(a){
if(a == 'a'){
getA();
}
}
}
return P
}())
var pclass = new PClass()
pclass.b //打印 變量b,外部可訪問
pclass.getB() //打印 變量b,外部可訪問 --- 獲取對象公有屬性b ---
console.log(pclass) //打印 P {b: "變量b,外部可訪問"}
// 經過對外開放的另外一方法咱們能夠獲取到了私有變量a
pclass.getType('a') //打印 私有變量 私有方法
複製代碼
根據上面的例子咱們不難發現,私有變量只能再閉包內部訪問,外部沒法訪問,當時這個方案並不完美,爲何這麼說,好比咱們再new 一個 pclass1 , 而後修改a屬性的值,你會發現pclass的a值也發生了變化函數
var pclass1 = new PClass();
pclass1.setType('a', '修改私有屬性a的值');
pclass1.getType('a'); //打印 修改私有屬性a的值 私有方法
pclass.getType('a'); //打印 修改私有屬性a的值 私有方法
複製代碼
那麼針對上面的問題咱們怎麼解決呢;其實很簡單,咱們只要將這個閉包改爲非自執行函數就OK了ui
var pClass = function(){
var a = '私有變量';
var getA = function(){
console.log(a, '私有方法')
}
var setA = function(val){
a = val
}
function P (){
this.b = '變量b,外部可訪問'
}
P.prototype = {
getB : function(){
console.log(this.b,'--- 獲取對象公有屬性b ---')
},
setType: function(a,val){
if(a == 'a'){
setA(val);
}
},
getType: function(a){
if(a == 'a'){
getA();
}
}
}
return P
}
var PClass1 = pClass(); //開闢了一個函數做用域
var PClass2 = pClass(); //從新開闢了一個函數做用域
var pclass1 = new PClass1();
var pclass2 = new PClass2();
pclass1.setType('a', '修改私有屬性a的值');
pclass1.getType('a'); //打印 修改私有屬性a的值 私有方法
pclass2.getType('a'); //打印 私有變量 私有方法
複製代碼
先來解釋下symbol類型;Symbol值經過Symbol函數生成。這就是說,對象的屬性名如今能夠有兩種類型,一種是原來就有的字符串,另外一種就是新增的Symbol類型。凡是屬性名屬於Symbol類型,就都是獨一無二的,能夠保證不會與其餘屬性名產生衝突;相似與UUID的用法。this
Symbol('1') == Symbol('1') //打印 false
var sy = sb = Symbol('a');
sy === sb //打印 true 說明該數據類型以引用的方式傳值。
複製代碼
解釋了Symbol 類型數據,那下面來寫一個基於Symbol類型的私有變量,私有屬性吧。spa
var Pclass = (function(){
const a = Symbol('a');
const m = Symbol('m');
class Pclass {
constructor(){
this[a] = 'a這是私有變量';
this.b = '變量B-外部可訪問';
this[m] = function(){
console.log('私有方法');
}
}
getA(){
console.log(this[a]);
}
getM(){
console.log(this[m]);
}
}
return Pclass
}())
let pc = new Pclass()
console.log(pc) //打印 Pclass {b: "變量B-外部可訪問", Symbol(a): "這是私有變量", Symbol(m): ƒ}
複製代碼
由上述代碼咱們能夠發現 只要不把 a = Symbol('a'); m = Symbol('m') 這兩個引用對外暴露,外部是沒法訪問到定義的私有變量a,和私有方法m, 由於他們的真實屬性名稱是a, m 這兩個引用,並且是惟一的。prototype
先來解釋下WeakMap類型, 該類型數據是一個鍵-值(key-val)對的集合,只不過他的鍵(key)是一個引用,不一樣於通常的鍵-值。WeakMap 的使用以下。code
const wm = new WeakMap();
const a = {}, b = {};
wm.set(a, '這是a對象鍵的值');
wm.set(b, '這是b對象鍵的值');
console.log(wm.get(a)) //打印 這是a對象鍵的值
console.log(wm.get(b)) //打印 這是b對象鍵的值
複製代碼
解釋了WeakMap類型數據,那下面來寫一個基於WeakMap類型的私有變量,私有屬性吧。對象
var Pclass = (function(){
const aa = new WeakMap();
const mt = new WeakMap();
class Pclass {
constructor(){
this.b = 'b這是公有變量';
aa.set(this, '私有變量aa')
mt.set(this, function(){
console.log('私有方法mt')
})
}
getA(){
console.log(aa.get(this));
}
getM(){
console.log(mt.get(this));
}
}
return Pclass
}())
let pc = new Pclass()
console.log(pc) // Pclass {b: "b這是公有變量"}
複製代碼
同上述代碼咱們能夠發現 只要不把 aa = new WeakMap(); m = new WeakMap()這兩個集合對外開放 外部是沒法訪問到定義的私有變量a,和私有方法m, 由於他們的真實屬性名稱是a, m 這兩個引用,並且是惟一的。ip