You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript中能否隐藏对象属性?自定义Set类实现疑问

重写Set时如何隐藏size属性且无需额外cache属性?

需求说明

声明一个函数Collection,接收一个数组作为参数,使用new关键字调用时返回Collection对象实例。
Collection对象功能与Set类似——存储唯一值(无重复),键与值相同。
所有Collection对象需包含自身的size属性,用于跟踪元素数量,初始化时size为0。

我的初始实现(含cache属性)

function Collection (arr) {
  // size property initialized to 0
  this.size = 0;
  // cache property to store unique arr elements
  this.cache = {}

  // loop thru input arr
  for (let i = 0; i < arr.length; i++) {
    // if the current arr element is not a key in the cache prop, create a key/val pair 
    if (!this.cache[arr[i]]) {
      // key and value are the same
      this.cache[arr[i]] = arr[i];
      // increment the size prop
      this.size ++;
    };
  };
}

测试结果

const testObj = new Collection([1, 2, 2, 3, true, true, 'hi', 'hi'])
console.log(testObj.cache); // {'1': 1, '2': 2, '3': 3, 'true': true, 'hi': 'hi'}
console.log(testObj.size); // -> 5

通过cache存储元素可以避免打印对象时显示元素,但额外多了一个cache属性,不够简洁。

第二种实现(无cache但size可见)

function Collection (arr) {
  // size property initialized to 0
  this.size = 0;

  // loop thru input arr
  for (let i = 0; i < arr.length; i++) {
    // if the current arr element is not a key in the cache prop, create a key/val pair 
    if (!this[arr[i]]) {
      // key and value are the same
      this[arr[i]] = arr[i];
      // increment the size prop
      this.size ++;
    };
  };
}

测试结果

const testObj = new Collection([1, 2, 2, 3, true, true, 'hi', 'hi'])
console.log(testObj); // {'1': 1, '2': 2, '3': 3, size: 5, 'true': true, 'hi': 'hi'}
console.log(testObj.size); // -> 5

这种方式去掉了cache,但打印对象时size属性会暴露出来,不符合预期。

问题

如何隐藏对象的size属性,同时无需额外声明cache属性?


解决方案

方案1:使用Object.defineProperty定义不可枚举的size属性

通过Object.defineProperty把size设置为不可枚举,打印对象时不会显示该属性,但仍能正常访问。

function Collection(arr) {
  let _size = 0; // 用私有变量存储实际数值

  // 定义不可枚举的size属性
  Object.defineProperty(this, 'size', {
    get() {
      return _size;
    },
    enumerable: false, // 关键:设置为**不可枚举**
    configurable: true
  });

  for (let i = 0; i < arr.length; i++) {
    const item = arr[i];
    if (!this[item]) {
      this[item] = item;
      _size++;
    }
  }
}

测试结果

const testObj = new Collection([1, 2, 2, 3, true, true, 'hi', 'hi'])
console.log(testObj); // {'1': 1, '2': 2, '3': 3, 'true': true, 'hi': 'hi'}
console.log(testObj.size); // -> 5

方案2:使用ES6类的私有字段(更优雅)

如果环境支持ES6+,可以用类的私有字段(#前缀)存储size,彻底隐藏内部变量,同时通过getter暴露size属性。

class Collection {
  #size = 0; // 私有字段,外部无法直接访问

  constructor(arr) {
    for (const item of arr) {
      if (!this[item]) {
        this[item] = item;
        this.#size++;
      }
    }
  }

  // 定义可访问的size getter
  get size() {
    return this.#size;
  }
}

测试结果

const testObj = new Collection([1, 2, 2, 3, true, true, 'hi', 'hi'])
console.log(testObj); // {'1': 1, '2': 2, '3': 3, 'true': true, 'hi': 'hi'}
console.log(testObj.size); // -> 5
console.log(testObj.#size); // 报错:私有字段不可访问

内容的提问来源于stack exchange,提问作者user19809568

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 11:41:03