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
相关产品推荐
相关产品推荐

