Skip to content

title: 私有变量 tags: [JavaScript手写题]

私有变量

通常,私有属性有一个约定,例如以_开头的属性是私有属性变量,我们不能对这一类成员访问和操作。

在以前的JavaScript是没有私有属性的说法,但像函数内部,块级作用域中的变量可以并认为是私有的,因为外部无法访问到它,

ES提案

后来有个类私有属性的提案,让JavaScript可以直接在类中成员属性前面追加#,代表它是私有属性。

js
class Foo{
    #bar = 0;
}

bar为私有变量

Class field declarations for JavaScript

Proxy

通过Proxy对象拦截私有属性的获取操作

js
function proxy(obj) {
    return new Proxy(obj, {
        get(target, key) {
            if (/^_/.test(key)) {
                throw new Error(`${key} is private`)
            } else {
                return target[key]
            }
        },
        set(target, key) {
            if (/^_/.test(key)) {
                throw new Error(`${key} is private, cannot be modified`)
            }
        },
        // 遍历时拦截处理
        ownKeys(target) {
            return target.ownKeys(target).filter(key => !!!/^_/.test(key))
        }
    })
}

console.log(fooProxy) // {name: 'island', _age: 18}
console.log(fooProxy.name) // island
console.log(fooProxy._age) // Error: _age is private

Symbol

利用Symbol标签的唯一性,将带_开头的属性替换成symbolKey,使得外部无法访问。

js

function sym(obj) {
    const result = {}
    for (const key in obj) {
        if (/^_/.test(key)) {
            const symbolKey = Symbol(key)
            result[symbolKey] = obj[key]
        } else {
            result[key] = obj[key]
        }
        return result
    }
}

const fooSym = sym({ name: 'island', _age: 18 })
console.log(fooSym) // {name: 'island'}

closure

利用闭包的特性,内部可以访问得到私有属性,返回给外部一个不带私有属性的对象。

js

const closure = function (obj) {
    return (function () {
        console.log(Object.keys(obj).filter(i => /^_/.test(i)))
        return Object.keys(obj).filter(i => !/^_/.test(i))
    })()
}

const fooClo = closure({ name: 'island', _age: 18 })
console.log(fooClo) // {name: 'island'}