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

JS动态创建嵌套对象getter访问器时如何引用父对象属性

问题:JS嵌套对象的getter如何访问父级作用域属性

我不确定该如何清晰表述该问题,以下代码片段可直观展示我的开发场景:我定义了如下JS类:

// This is my current Implementation of code
Class OptionCls {
  Constructor(){
    this.dataObj = {
      name: '',
      selectedValue: '',
      options: [],  
    }
  }

  setOptions(optionArray){
    this.dataObj.options = this.prepareOptions(optionArray);
  }

  prepareOptions(options){
    for(let obj of options){
        obj.label = obj.label ? obj.label : '';
        obj.value = obj.value ? obj.value : '';
        // automated properties for dropdown options
        Object.defineProperty(obj, '_id', {
            value: uniqueId()
        });
     }
     return options;
  }

  // class end
}

我调用setOptions()方法并传入对象数组,为dataObj.options属性赋值。

目前我需要在dataObj.options的每个子项上定义名为selected的getter访问器属性,该属性需要自动读取父级属性dataObj.selectedValue,基于该值判断当前选项是否为选中状态,我初步的实现思路如下:

prepareOptions(options){
   for(let obj of options){
        obj.label = obj.label ? obj.label : '';
        obj.value = obj.value ? obj.value : '';
        // automated properties for dropdown options
        Object.defineProperty(obj, '_id', {
            value: uniqueId()
        });
        Object.defineProperty(obj, 'selected', {
            get(){
               return this.dataObj.selectedValue.split(',').includes(this.value); // Now over here `this` will be refer to local this scope not the parent object
            }
        });
    }
    return options;
}

最终dataObj的输出结构需要符合如下预期:

{
  name: '',
  selectedValue: 'us,uk',
  options: [
     {
       _id: "13",
       label: "United States",
       value: "us",
       selected: true
     },
     {
       _id: "11",
       label: "Australia",
       value: "au",
       selected: false
     },
     {
       _id: "10",
       label: "United Kingdom",
       value: "uk",
       selected: true
     }
  ]  
}

上述实现的问题:getter函数内部的this指向当前嵌套的选项对象本身,无法引用父对象的selectedValue属性。


解决方案

问题本质是JS的this绑定规则:对象方法/getter执行时,this默认指向当前挂载该方法的对象,也就是单个选项实例,自然拿不到外层类实例上的dataObj。直接用闭包捕获外层作用域的dataObj引用即可,不需要给选项对象加反向父级引用这类冗余设计。

修正后的prepareOptions代码如下:

prepareOptions(options){
   // 提前捕获父级dataObj的引用,供内部getter闭包访问
   const parentData = this.dataObj;
   for(let obj of options){
        obj.label = obj.label || '';
        obj.value = obj.value || '';
        // 注意加enumerable: true,否则属性默认不可枚举,打印/序列化时看不到
        Object.defineProperty(obj, '_id', {
            value: uniqueId(),
            enumerable: true
        });
        Object.defineProperty(obj, 'selected', {
            enumerable: true,
            get(){
               // 加空值兜底,避免selectedValue为空时split抛错
               const selectedList = parentData.selectedValue ? parentData.selectedValue.split(',') : [];
               return selectedList.includes(this.value);
            }
        });
    }
    return options;
}

实现说明

  • 闭包捕获的parentData是对dataObj的直接引用,后续修改dataObj.selectedValue时,所有选项的selected状态会自动实时计算,不需要手动遍历更新选项状态。
  • 补充enumerable: true配置:Object.defineProperty定义的属性默认不可枚举,不加这个配置的话,打印对象、调用JSON.stringify序列化时都看不到_id和selected属性,和预期输出结构不符。
  • 增加空值兜底:当selectedValue为空字符串、null或undefined时,直接返回空数组做匹配,不会触发split方法的类型报错。
  • 不需要在选项对象上额外存储父级引用,不会污染选项的原始数据结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 15:54:07