2种Javascript对象private属性/方法封装方式

297 阅读1分钟

要对Javascript对象封装的时候,常常遇到一种需求,就是隐藏其部分属性/方法,使之变成private作用域

const person = {
  name: 'Tom'
};

person.name = 'John';

如果想要person调用的时候不能直接访问name,很自然的想到对name字段做setter/getter封装

const person = {
  _name: 'Tom',
  setName(name) {
    this._name = name;
  },
  getName() {
    return this._name;
  }
};

person.setName('John');
// 这样的写法还是无法阻止对_name赋值
person._name = 'Kate';

因为JS语言不像Java/C#有private关键字,这样的方式并不能阻止对_name赋值。 那么我们有没有办法做到让_name完全无法访问?

方法一

对person对象进行再次封装输出

const person = {
  _name: 'Tom',
  setName(name) {
    this._name = name;
  },
  getName() {
    return this._name;
  },
  wrap() {
    // 将可以被公开访问的方法/字段放在这里
    const t = this;
    return {
      setName(name) {
        t.setName(name);
      },
      getName() {
        return t.getName();
      }
    };
  }
};

const personWrap = person.wrap();

// 测试,personWrap中因为没有_name,所以只能通过setName访问
personWrap.setName('John');
console.log(personWrap.getName());

// 将重新封装的对象输出
export { personWrap };

方法二,使用Symbol

const _name = Symbol('name');

const person = {
  [_name]: 'Tom',
  setName(name) {
    this[_name] = name;
  },
  getName() {
    return this[_name];
  }
};

// 导出之后的person因为拿不到Symbol('name')就无法再访问这个属性
export { person };

对比起来,第二种方式写法更简单代码量更少,但是要注意IE不支持Symbol,第一种方法的兼容性更好。