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

JavaScript对象属性赋值:函数应返回对象却得到数组的问题

问题:设置对象属性时得到数组而非预期对象

我尝试用一个返回对象的函数来设置对象的属性,但设置时得到的是数组而非预期的对象。

代码示例

const newUserRights = {
  A: { id: '1'},
  B: { id: '2'},
  C: { id: '3'},
  D: { id: '4'},
  E: { id: '5'},
  F: { id: '6'},
  G: { id: '7'},
};

var Post = {
  name: '',
  rs: function r(rights = []) {
    let r = {};
    for (let [k, v] of Object.entries(newUserRights)) {
      r[v.id] = false;
    }
    if (rights.length > 0) {
      for (ri of rights) {
        r[ri] = true;
      }
    }
    return r;
  },
};

// 尝试设置属性
Post.rs = ['1', '2'];

期望输出

Post: {
    name:'',
    rs:{
        1: true,
        2: true,
        3: false,
        4: false,
        5: false,
        6: false,
        7: false
    }
}

实际输出

Post: {
    name:'',
    rs:['1', '2']
}

问题解答

1. 错误原因

你直接把数组赋值给了Post.rs,完全覆盖了原本定义的函数。rs原本是Post对象的一个方法,但Post.rs = ['1', '2']这行代码直接替换了这个方法的引用,把它改成了数组,自然不会执行函数逻辑得到预期对象。另外原函数里的for (ri of rights)没有声明变量,会导致ri变成全局变量,属于语法隐患。

2. 实现预期效果的方法

不要直接赋值覆盖方法,而是调用方法并将返回值赋值给目标属性,有三种常见方式:

方式一:直接调用原方法覆盖rs

// 调用rs方法并传入权限数组,将返回的对象赋值给Post.rs
Post.rs = Post.rs(['1', '2']);

注意:这样操作后rs就从方法变成了普通对象,后续无法再调用它生成新的权限映射。

方式二:分离方法与属性(更推荐)

把生成权限映射的方法和存储结果的属性分开,避免误覆盖:

const newUserRights = {
  A: { id: '1'},
  B: { id: '2'},
  C: { id: '3'},
  D: { id: '4'},
  E: { id: '5'},
  F: { id: '6'},
  G: { id: '7'},
};

var Post = {
  name: '',
  // 专门的生成方法
  generateRightsMap: function(rights = []) {
    let r = {};
    for (let [k, v] of Object.entries(newUserRights)) {
      r[v.id] = false;
    }
    // 修复变量声明问题
    for (const ri of rights) {
      r[ri] = true;
    }
    return r;
  },
  // 存储权限映射的属性
  rs: {}
};

// 调用方法生成对象并赋值
Post.rs = Post.generateRightsMap(['1', '2']);

方式三:使用getter自动计算(更优雅)

通过getter函数,每次访问rs时自动计算返回对象,同时用setter维护原始权限数据:

const newUserRights = {
  A: { id: '1'},
  B: { id: '2'},
  C: { id: '3'},
  D: { id: '4'},
  E: { id: '5'},
  F: { id: '6'},
  G: { id: '7'},
};

var Post = {
  name: '',
  // 私有变量存储原始权限数组(约定下划线开头表示内部属性)
  _rawRights: [],
  // 访问rs时自动计算返回映射对象
  get rs() {
    let r = {};
    for (let [k, v] of Object.entries(newUserRights)) {
      r[v.id] = false;
    }
    for (const ri of this._rawRights) {
      r[ri] = true;
    }
    return r;
  },
  // 提供setter来更新原始权限
  set rights(rightsArr) {
    this._rawRights = rightsArr;
  }
};

// 使用方式:设置权限数组
Post.rights = ['1', '2'];
// 访问rs即可得到预期对象
console.log(Post.rs);

3. 实现方式的合理性分析

你原本的写法不算良好实践,存在以下问题:

  • 方法与属性同名,极易发生误覆盖,就像你这次遇到的问题;
  • 函数内部存在未声明变量的语法隐患,可能导致全局变量污染;
  • 缺乏封装性,直接暴露方法让用户手动处理赋值,容易出错。

推荐使用分离方法与属性或getter/setter的方式,前者逻辑清晰不易出错,后者能实现动态计算的封装效果,更符合JavaScript的面向对象实践规范。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 19:55:21