Object.assign(...)试图设置没有setter的属性。

3

当在一个对象上特别定义只读属性,并试图在原有的对象基础上分配另一个对象时,Object.assign似乎并不关心目标属性是否是只读的:

var myObj = {
    firstName: "Jimbo",
  lastName: "Smythe"
};

Object.defineProperty(myObj, "fullName", {
    get: function () {
    return this.firstName + " " + this.lastName;
  }
});

Object.assign(myObj, {
  fullName: "Jimbo T. Smythe"
});

这会导致以下异常:

类型错误:不能为仅有getter的#设置fullName属性

这不是 Object.assign中的一个bug吗?

完整的示例在这里:https://jsfiddle.net/fa8j7p5j/


如果出现错误,例如属性不可写,将引发TypeError,并且目标对象保持不变。 - Yury Tarabanko
1
我不明白问题出在哪里,它会抛出一个错误,你还能期望什么? - Omri Aharon
在规范 https://tc39.github.io/ecma262/#sec-object.assign 的 4.c.ii.2 中,Set(to, nextKey, propValue, true) 中的最后一个 true 表示如果失败就抛出 TypeError。 - Yury Tarabanko
1
@OmriAharon 我本来以为它会跳过只读属性,因为它们永远不会被写入。 - Josh M.
那可能是你所期望的差距吧。肯定不是一个错误 :) - Omri Aharon
显示剩余2条评论
1个回答

2

所以我认为真正的问题在于之前的Object.assign从未遇到可能引发异常的情况。现在有了只读属性,就会出现这种情况。现在没有办法盲目地在两个未知对象上使用assign,因为它可能会出错。

不幸的是,在添加新的Object.assignSafe方法之前,唯一的解决方法就是保护这些不良属性。

/**
 * This function performs an Object.assign but does not explode on trying to set a read-only property
 * @param  {Object} target  Target to apply sources properties to
 * @param  {Array<Object>} sources Any number of sources to be applied to target
 * @return {Object}        The updated target object;
 */
function assignSafe(target, ...sources) {
    const proto = Object.getPrototypeOf(target);
    const safe = sources.map(source => {
        let entries = Object.entries(source);
        let reduced = entries.reduce((accumulator, currentValue) => {
            const descriptor = Object.getOwnPropertyDescriptor(proto, currentValue[0]);
            if (!descriptor || descriptor.set) {
                accumulator.push(currentValue);
            }
            return accumulator;
        }, []);
        return Object.fromEntries(reduced);
    });
    return Object.assign(target, ...safe);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接