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

如何用Proxy或Object.defineProperty实现二维数组的行列双向读写封装?

二维数组双向维度读写包装器实现方案

问题描述

需要为二维数组创建一个包装器,支持以下操作且所有读写操作同步到原数组(通过引用同步):

  • 读写单行(原生数组默认支持)
  • 读写单列
  • 从列维度读写单个单元格

期望效果示例:

function myFunction() {
  var myArray = [['a1','b1'],['a2','b2']];

  var ds = new DataStructure(myArray);
  console.log(ds) // -> [['a1','b1'],['a2','b2']]

  console.log(ds[0]) // -> ['a1','b1']
  console.log(ds[1]) // -> ['a2','b2']

  console.log(ds.cols[0]) // -> ['a1','a2']
  console.log(ds.cols[1]) // -> ['b1','b2']
  ds.cols[0] = ['A1','A2']
  console.log(ds.cols[0]) // -> ['A1','A2']
  ds.cols[1][1] = 'Q2'
  console.log(ds.cols[1]) // -> ['b1','Q2']

  console.log(ds) // -> [['A1','b1'],['A2','Q2']]
  console.log(myArray) // -> [['A1','b1'],['A2','Q2']]
}

之前尝试用Proxy()和Object.defineProperty()实现,但访问列的深层元素(如ds.cols[0][0])时无法同步修改原数组,需要解决这个问题。

解决方案:嵌套Proxy实现双向同步

核心思路是用多层Proxy分别处理:

  1. 包装器实例的行访问与cols属性获取
  2. cols对象的列获取与赋值
  3. 列数组的元素读写,确保修改列元素时同步更新原数组的对应位置

完整实现代码

class DataStructure {
  constructor(originalArray) {
    this.original = originalArray;

    // 列代理:处理cols的列获取与赋值
    const colsProxy = new Proxy({}, {
      get: (_, colIndex) => {
        // 返回列的代理数组,实现元素读写同步
        return new Proxy([], {
          get: (_, rowIndex) => {
            return this.original[rowIndex][colIndex];
          },
          set: (_, rowIndex, value) => {
            this.original[rowIndex][colIndex] = value;
            return true;
          },
          // 支持列数组的长度获取
          getOwnPropertyDescriptor: (_, prop) => {
            if (prop === 'length') {
              return { value: this.original.length };
            }
            return Object.getOwnPropertyDescriptor([], prop);
          },
          // 遍历列元素
          ownKeys: () => {
            return [...Array(this.original.length).keys(), 'length'];
          }
        });
      },
      set: (_, colIndex, newColArray) => {
        // 赋值整列时,同步更新原数组的每一行对应列
        for (let rowIndex = 0; rowIndex < this.original.length; rowIndex++) {
          this.original[rowIndex][colIndex] = rowIndex < newColArray.length ? newColArray[rowIndex] : undefined;
        }
        return true;
      }
    });

    // 实例代理:处理行访问与cols属性
    return new Proxy(this, {
      get: (target, prop) => {
        if (prop === 'cols') {
          return colsProxy;
        }
        // 处理行索引访问
        if (!isNaN(Number(prop))) {
          return target.original[prop];
        }
        // 其他属性正常返回
        return Reflect.get(target, prop);
      },
      set: (target, prop, value) => {
        // 处理行赋值
        if (!isNaN(Number(prop))) {
          target.original[prop] = value;
          return true;
        }
        return Reflect.set(target, prop, value);
      },
      // 让实例能被正常遍历和转换为数组
      getOwnPropertyDescriptor: (target, prop) => {
        if (!isNaN(Number(prop)) && Number(prop) < target.original.length) {
          return Object.getOwnPropertyDescriptor(target.original, prop);
        }
        return Reflect.getOwnPropertyDescriptor(target, prop);
      },
      ownKeys: (target) => {
        return [...Array(target.original.length).keys(), ...Reflect.ownKeys(target)];
      }
    });
  }
}

代码说明

  1. 实例Proxy:

    • 拦截行索引的读写,直接映射到原数组的对应行
    • 拦截cols属性的获取,返回列代理对象
    • 实现数组的遍历和长度相关特性,确保console.log(ds)能正常输出数组结构
  2. 列Proxy:

    • 拦截列索引的获取,返回一个代理数组
    • 拦截列的赋值操作,将新数组的每个元素同步到原数组的对应行的列位置
  3. 列元素Proxy:

    • 对每个列的数组做代理,拦截元素的读写操作,直接映射到原数组的original[rowIndex][colIndex]位置
    • 实现length属性和遍历特性,让列数组表现得像普通数组

测试验证

运行修正后的测试函数,所有操作都会同步到原数组,包括列的深层元素修改。


内容的提问来源于stack exchange,提问作者Christian Schäfer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 14:57:06