JS 私有变量:私房钱的三种藏法

42 阅读2分钟
  • 闭包 closure

  • 私有属性要求:

    • 不能被外界访问到
    • 不能被多个实例共享

用闭包实现私有变量

const creatingFn = (function () {
    let data//被保存的数据
    class InsideClass {
        constructor(val) {
            data = val//捆绑作用域外参数
        }
        getDate() {
            return data
        }
    }
    return InsideClass
})()//立刻执行函数
console.log(new creatingFn(1).getDate())//1
console.log(new creatingFn(2).getDate())//2
console.log(new creatingFn(3).getDate())//3

用symbol加闭包实现私有变量

//用闭包加symbol实现私有变量
const creatingFn = (function () {
    let data = Symbol('data')
    class InsideClass {
        constructor(val) {
            this[data] = val
        }
        getData() {
            return this[data]
        }
    }
    return InsideClass
})()
let fn1 = new creatingFn(1)
console.log(fn1.getData())//1
let fn2 = new creatingFn(2)
console.log(fn2.getData())//2
let fn3 = new creatingFn(3)
console.log(fn3.getData())//3
console.log(fn3[Object.getOwnPropertySymbols(fn3)[0]])//Symbol反而坏事了

⚠️ 可以被其他的方法访问,就不私有了

用weakMap实现私有变量

思路就是将私有变量的值作为弱映射的值,不知道键的时候就无法访问,键是对象实例

const creatingFn = (function () {
    let data = new WeakMap()
    class InsideClass {
        constructor(val) {
            data.set(this, val)
        }
        getData() {
            return data.get(this)
        }
    }
    return InsideClass
})()
let fn1 = new creatingFn(1)
let fn2 = new creatingFn(2)
let fn3 = new creatingFn(3)
console.log(fn1.getData(), fn2.getData(), fn3.getData())

升级版 闭包 WeakMap 私有变量 集

//升级版weakMap闭包私有函数
//在privateDataMap里面值是privateDataSet,privateData也是键值对键叫property,对应的privateDate就是我们要存储的私有变量
const SuperPrivate = (() => {
    let privateDateMap = new WeakMap()//不是只有一个私有变量,每一个实例都可以保存很多个私有变量
    class Private {
        constructor(id) {//创建的时候有一个id,这个id也必须是私有函数
            this.idProperty = Symbol("initialId")//这是我们这个实例创建的id的键
            this.setProperty(this.idProperty, id)
        }
        setProperty(property, privateData) {
            //注意这里一开始是没有键的,第一次是要创建的,我们用一个断言
            const privateDataSet = privateDateMap.get(this) || {}
            privateDataSet[property] = privateData//推入privataData到privateDataSet中
            console.log(privateDataSet)
            privateDateMap.set(this, privateDataSet)//保存到weakmap中
        }
        getProperty(property) {
            return privateDateMap.get(this)[property]
        }
        getId() {
            return this.getProperty(this.idProperty)
        }
    }
    return Private
}
)()
let testing1 = new SuperPrivate(123)
console.log(testing1.getId())
testing1.setProperty('password', 456)
console.log(testing1.getProperty('password'))

//如果不是闭包的话可以这样访问


privateMap.get(testing1)[testing1.idProperty]
privateMap.get(testing1)[property]
//那就不妙了