`Object.assign()`的polyfill中,`Object(target)`的目的是什么?

6
MDN页面Object.assign()中,示例polyfill首先将所有源和目标参数都包装在Object()中,然后再迭代属性。 (即Object(target)Object(source1)Object(source2) ...)。
文本还提到,在返回目标之前,附加属性直接添加到目标中。但是,在Object()中包装目标会导致一个不同于简单增强属性的对象。 (即Object(target).newProp !== target.newProp)。
所有给出的示例都将对象作为参数传递给Object.assign()。因此,非对象源或目标参数的用例不清楚。 A)将参数包装在Object()中的目的是什么? (我认为Object.keys(x)Object.keys(Object(x))相同。) B)使用非对象调用Object.assign()的可能用例是什么(例如:Object.assign(1, 'b', [3], true, function(){}))?

2
Object(target)将目标转换为对象。例如:Object("1234")将其转换为[object String] {0: "1", 1: "2", 2: "3", 3: "4", length: 4} - Mouser
5
通常最好与polyfill一起阅读规范,因为它们通常试图复制行为。从ed. 6 draft中可以看出,每个参数都传递给了ToObject。由于本地脚本无法访问内部方法,调用Object(target)Object(source)是一种近似(尽管对于* null undefined *来说并不完全相同)。 - RobG
@Mouser。我明白Object()的作用是什么。但我不明白为什么你会做类似Object.assign([], 'a', 3, function(){})这样的事情。 - Hurelu
当您有一个具有属性的对象需要传输到另一个对象时:当您需要更改对象A的属性,但希望让A保持不变时,您可以将属性复制到B并更改它们,就像您使用slice复制数组的一部分一样。 - Mouser
@Mouser。我知道如何在对象之间传递属性。我经常这样做。但我不明白的是为什么polyfill使用Object.keys(Object(x))而不是简单地使用Object.keys(x)。我错过了什么吗? - Hurelu
显示剩余2条评论
1个回答

2

让我们来分解一下:

测试对象是否存在,如果不存在则创建:

if (!Object.assign) {

通过使用Object.defineProperty方法,将其添加到Object中。
    Object.defineProperty(Object, 'assign', {
    enumerable: false,
    configurable: true,
    writable: true,

这里设置了实际的功能。至少需要提供一个目标和一个源。

    value: function(target, firstSource) {
      'use strict';

如果目标未定义,则抛出错误。
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert first argument to object');
      }

将目标转换为对象格式。 (例如,将字符串 1234 转换为[object String] {0:“1”,1:“2”,2:“3”,3:“4”,length:4}

      var to = Object(target);

现在使用函数的参数对象循环遍历所有来源。从1开始,因为0是目标。
      for (var i = 1; i < arguments.length; i++) {
        var nextSource = arguments[i]; //store the argument in a variable.
        if (nextSource === undefined || nextSource === null) {
          continue; //if the source is undefined continue. 
        }

然后我们需要从源对象中获取所有(不仅是公开的)可枚举属性,使用Object.keysObject(source)相结合。
        var keysArray = Object.keys(Object(nextSource));

Iterate over the keys:

        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
          var nextKey = keysArray[nextIndex]; //select the key from the index.

getOwnPropertyDescriptor 方法以对象形式提供了有关属性的信息。

          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);

如果属性不是未定义的并且可枚举,则将此属性设置为 to 的属性。
          if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
      return to;
    }
  });
}

最后将新添加的(克隆的)属性返回to


很好,但执行 var to = Object(target); 的原因并不是为了“代码可以枚举属性”,而是如果目标不是一个对象(例如 1),则无法向其分配属性。没有对目标属性的循环来支持这种说法。 - Dan D.
是的,它从不枚举它们。它只是转换为一个对象。 - Mouser
抱歉,我还是不明白。在 polyfill 中,我不理解的部分(因此提出了问题)是“将目标转换为对象格式”的步骤。我使用 Object.keys('abcd')Object.keys(Object('abcd')) 得到相同的结果,因此我猜测包装是为了其他我尚未想到的用途。 - Hurelu
@Dan D. 鉴于这个问题,为什么还要包装源代码?为什么会在非对象上使用Object assign?我已经尝试过带有和不带有Object()转换的Object.keys(),结果总是相同的。 - Hurelu
Object.keys('abcd') 在 IE11 中会失败,显示 Object.keys: argument is not an object,但 Object.keys(Object('abcd')) 不会失败。 - Mouser
@Mouser。谢谢。这是一个不错的提示,因为我只是在Chrome控制台上玩耍。我刚刚检查过,在Firefox中Object.key('abc')也可以工作。答案可能在于Object.keys()规范和浏览器之间的不同实现。 - Hurelu

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