Array.prototype 的方法在使用 jQuery.extend 深度克隆后显示为数组的键

Methods of Array.prototype appear as keys of array after deep cloning with jQuery.extend

假设数组原型已经增加了一些辅助函数:

Array.prototype.doSomething = function() { ... }

当我将一个简单数组注销到控制台时...

console.dir([1,2,3]);

...我得到:

Array [3]
    0: 1
    1: 2
    2: 3
    length: 3
    __proto__: Array[0]
       doSomething: function()

到目前为止一切看起来都很好。

但是一旦我使用 $.extend 深度克隆数组(深度克隆因为我的实际数据更复杂 - 一个以数组作为属性的对象,但它在任何情况下都会发生)...

$.extend(true, [], [1,2,3]);

我突然得到:

Array [3]
    0: 1
    1: 2
    2: 3
    doSomething: function()     // ???
    length: 3
    __proto__: Array[0]
       doSomething: function() 

看起来原型方法已添加为数组实例的实际项。

在复制之前 JQuery.extend 是否没有测试 hasOwnProperty(),还是我做错了什么?

这似乎是文档中 $.extend 规范的一部分:

"However, properties inherited from the object's prototype will be copied over."

https://api.jquery.com/jquery.extend/

Does JQuery.extend not test for hasOwnProperty() before copying

不,它没有。从源代码来看,它使用 for ... in 循环来遍历正在克隆的任何内容的属性,但在设置属性之前不进行 hasOwnProperty 检查。

https://github.com/jquery/jquery/blob/7103d8ef47e04a4cf373abee0e8bfa9062fd616f/src/core.js#L120

jQuery.extend = jQuery.fn.extend = function() {
  var options, name, src, copy, copyIsArray, clone,
      target = arguments[ 0 ] || {},
      i = 1,
      length = arguments.length,
      deep = false;

  // Handle a deep copy situation
  if ( typeof target === "boolean" ) {
      deep = target;

      // Skip the boolean and the target
      target = arguments[ i ] || {};
      i++;
  }

  // Handle case when target is a string or something (possible in deep copy)
  if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
      target = {};
  }

  // Extend jQuery itself if only one argument is passed
  if ( i === length ) {
      target = this;
      i--;
  }

  for ( ; i < length; i++ ) {

      // Only deal with non-null/undefined values
      if ( ( options = arguments[ i ] ) != null ) {

          // Extend the base object
          for ( name in options ) {
              src = target[ name ];
              copy = options[ name ];

              // Prevent never-ending loop
              if ( target === copy ) {
                  continue;
              }

              // Recurse if we're merging plain objects or arrays
              if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
                  ( copyIsArray = jQuery.isArray( copy ) ) ) ) {

                  if ( copyIsArray ) {
                      copyIsArray = false;
                      clone = src && jQuery.isArray( src ) ? src : [];

                  } else {
                      clone = src && jQuery.isPlainObject( src ) ? src : {};
                  }

                  // Never move original objects, clone them
                  target[ name ] = jQuery.extend( deep, clone, copy );

              // Don't bring in undefined values
              } else if ( copy !== undefined ) {
                  target[ name ] = copy;
              }
          }
      }
  }

  // Return the modified object
  return target;
};

它会影响你的阵列数据吗?根据您使用数组的方式,可能不会。只要您使用正确的循环过程,迭代数组元素仍然是相同的。意思是 for(;;)for ... of.forEach。做 JSON.stringify 仍然会给你正确的 JSON.