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

