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

相关文章
相关标签/搜索