JavaScript如何實現私有變量私有方法

前言

你們都知道JavaScript不像Java這類強類型語言,有特定的字面量(private)來定義參數爲類的私有參數;那JavaScript如何能實現私有變量呢,下面來介紹幾種實現方式。閉包

1、函數做用域封裝局部變量的方式。

1.1 閉包定義局部變量(自執行函數)

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

1.2 閉包定義局部變量(非自執行函數)

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');   //打印 私有變量 私有方法
複製代碼

2、ES6 定義私有變量,私有方法

2.1 使用ES6擴展的類型symbol類型定義

先來解釋下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

2.1 使用ES6擴展的類型WeakMap類型定義

先來解釋下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

相關文章
相關標籤/搜索