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

时间:2016-02-13 16:04:51

标签: javascript jquery arrays clone extend

让我们说Array原型已经增加了一些辅助函数:

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(),或者我在这里做错了什么?

2 个答案:

答案 0 :(得分:1)

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

  

"但是,从对象原型继承的属性将被复制。"

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

答案 1 :(得分:1)

  

在复制

之前,JQuery.extend是否不测试hasOwnProperty()

不,不。从源代码开始,它使用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。