js引用类型赋值,深拷贝与浅拷贝

  JS中引用类型使用等号“=” 赋值,相当于把原来对象的地址拷贝一份给新的对象,这样原来旧的对象与新的对象就指向同一个地址,改变其中一个对象就会影响另外那个对象,也就是所谓的浅拷贝。例如:

var arr = ["One","Two","Three"];

var arrto = arr;
arrto[1] = "test";
document.writeln("数组的原始值:" + arr + "<br />");//Export:数组的原始值:One,test,Three
document.writeln("数组的新值:" + arrto + "<br />");//Export:数组的新值:One,test,Three

  其实很多时候这并不是我们想要的结果,修改新对象时我们希望不要影响原来的对象。

  今天我想说的是jQuery.extend()

jQuery.extend = jQuery.fn.extend = function() {
    var src, copyIsArray, copy, name, options, 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;
};

  $.extend(target,object1,objectN); 合并object1与objectN至target中,此操作会改变target的结构。

  若不想改变原来对象,可以设置第一个参数为一个空对象{}: $.extend({},object1,objectN);

  $.extend()第一个参数也可以为布尔类型,只是是否是深拷贝。$.extend(true,target,object1,objectN);设为true则表示深拷贝,不设默认为浅拷贝,此处只能设true,不能设false。

  The merge performed by $.extend() is not recursive by default; if a property of the first object is itself an object or array, it will be completely overwritten by a property with the same key in the second or subsequent object. The values are not merged. This can be seen in the example below by examining the value of banana. However, by passing true for the first function argument, objects will be recursively merged.

Warning: Passing false for the first argument is not supported.

  Undefined properties are not copied. However, properties inherited from the object‘s prototype will be copied over. Properties that are an object constructed via new MyCustomObject(args), or built-in JavaScript types such as Date or RegExp, are not re-constructed and will appear as plain Objects in the resulting object or array.

On a deep extend, Object and Array are extended, but object wrappers on primitive types such as String, Boolean, and Number are not. Deep-extending a cyclical data structure will result in an error.

For needs that fall outside of this behavior, write a custom extend method instead, or use a library like lodash.

Examples:

Example: Merge two objects, modifying the first.

 1 <!doctype html>
 2 <html lang="en">
 3 <head>
 4   <meta charset="utf-8">
 5   <title>jQuery.extend demo</title>
 6   <script src="https://code.jquery.com/jquery-1.10.2.js"></script>
 7 </head>
 8 <body>
 9
10 <div id="log"></div>
11
12 <script>
13 var object1 = {
14   apple: 0,
15   banana: { weight: 52, price: 100 },
16   cherry: 97
17 };
18 var object2 = {
19   banana: { price: 200 },
20   durian: 100
21 };
22
23 // Merge object2 into object1
24 $.extend( object1, object2 );
25
26 // Assuming JSON.stringify - not available in IE<8
27 $( "#log" ).append( JSON.stringify( object1 ) );
28 </script>
29
30 </body>
31 </html>

输出为:{"apple":0,"banana":{"price":200},"cherry":97,"durian":100}

object1.banana.price = 300; //改变object1中的banana对象的price属性为300
$( "#log" ).append( JSON.stringify( object1 ) ); //输出为 {"banana":{"price":300},"durian":100},object1的改变会影响object2

Example: Merge two objects recursively, modifying the first.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>jQuery.extend demo</title>
  <script src="https://code.jquery.com/jquery-1.10.2.js"></script>
</head>
<body>

<div id="log"></div>

<script>
var object1 = {
  apple: 0,
  banana: { weight: 52, price: 100 },
  cherry: 97
};
var object2 = {
  banana: { price: 200 },
  durian: 100
};

// Merge object2 into object1, recursively
$.extend( true, object1, object2 );

// Assuming JSON.stringify - not available in IE<8
$( "#log" ).append( JSON.stringify( object1 ) );
</script>

</body>
</html>

输出为:{"apple":0,"banana":{"weight":52,"price":200},"cherry":97,"durian":100}

 object1.banana.price = 300; //改变object1中的banana对象的price属性为300

   $( "#log" ).append( JSON.stringify( object1 ) ); //输出为 {"banana":{"price":200},"durian":100},object1的改变不会影响object2

Example: Merge defaults and options, without modifying the defaults. This is a common plugin development pattern.

 1 <!doctype html>
 2 <html lang="en">
 3 <head>
 4   <meta charset="utf-8">
 5   <title>jQuery.extend demo</title>
 6   <script src="https://code.jquery.com/jquery-1.10.2.js"></script>
 7 </head>
 8 <body>
 9
10 <div id="log"></div>
11
12 <script>
13 var defaults = { validate: false, limit: 5, name: "foo" };
14 var options = { validate: true, name: "bar" };
15
16 // Merge defaults and options, without modifying defaults
17 var settings = $.extend( {}, defaults, options );
18
19 // Assuming JSON.stringify - not available in IE<8
20 $( "#log" ).append( "<div><b>defaults -- </b>" + JSON.stringify( defaults ) + "</div>" );
21 $( "#log" ).append( "<div><b>options -- </b>" + JSON.stringify( options ) + "</div>" );
22 $( "#log" ).append( "<div><b>settings -- </b>" + JSON.stringify( settings ) + "</div>" );
23 </script>
24
25 </body>
26 </html>

输出为:

defaults -- {"validate":false,"limit":5,"name":"foo"}

options -- {"validate":true,"name":"bar"}

settings -- {"validate":true,"limit":5,"name":"bar"}

参考资料:jQuery.extend的实现方式

时间: 2024-11-02 17:59:24

js引用类型赋值,深拷贝与浅拷贝的相关文章

js 中引用类型 的深拷贝 和 浅拷贝的区别

一.曾经在读JQ源码的时候,对深拷贝算是有了一点的理解.我们在项目中是不是经常会遇到这样的问题呢? 后台返回一个数组对象(引用类型).次数在页面渲染中需要对部分数据进行处理 比如:银行卡62345092534 (这么长) 但在页面显示的时候, 只显示中国银行(3118)但是传给后台的时候.又要传623445242整个号码,我们也许会把var oldData = res.data; 但是我们发现两个数据都变了? 这是为什么呢? 其实就是一个深浅拷贝的问题. 二.浅拷贝 比如数组,对象,这样的引用类

浅谈js中的深拷贝和浅拷贝

1. 如果是基本数据类型(String,Number,Boolean,Null,undefined),名字和值都会储存在栈内存中.栈内存中的数据每一次赋值都会产生一个新的内存,每条数据之间不相互影响, var a = 1; b = a; // 栈内存会开辟一个新的内存空间,此时b和a都是相互独立的 b = 2; console.log(a); // 1 2. 如果是引用数据类型(Object),名字存在栈内存中,值存在堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值. 例如:var a=

js 中的 深拷贝与浅拷贝

js在平时的项目中,赋值操作是最多的:比如说: 1 var person1 = { 2 name:"张三", 3 age:18, 4 sex:"male", 5 height:180, 6 weight:14012 } 13 var person2 = person1; 14 console.log(person2) 15 person2.name = "李四"; 16 console.log(person1,person2); 这段代码,con

js中的深拷贝和浅拷贝

深复制和浅复制只针对像 Object, Array 这样的复杂对象的.简单来说,浅复制只复制一层对象的属性,而深复制则递归复制了所有层级. 深浅拷贝 的主要区别就是:复制的是引用(地址)还是复制的是实例. 所谓 深浅拷贝: 对于仅仅是复制了引用(地址),换句话说,复制了之后,原来的变量和新的变量指向同一个东西,彼此之间的操作会互相影响,为 浅拷贝. 而如果是在堆中重新分配内存,拥有不同的地址,但是值是一样的,复制后的对象与原来的对象是完全隔离,互不影响,为 深拷贝. 下面是一个简单的浅复制实现:

js 中的深拷贝和浅拷贝

 Shallow copy && Deep copy 对于字符串类型,浅复制是对值的复制,对于对象来说,浅复制是对对象地址的复制,并没 有开辟新的栈,也就是复制的结果是两个对象指向同一个地址,修改其中一个对象的属性,则另一个对象的属性也会改变, 举个栗子 var arr = [1,2,3]; var arrCopy = arr; arrCopy[0] = 100; // 修改新数组的第0个值: arr[0]===arrCopy[0]; //true 原来的数组四不四也变了 而很多数情况下我

js中的深拷贝与浅拷贝

对于字符串类型,浅拷贝是对值的拷贝,对于对象来说,浅拷贝是对对象地址的拷贝,并没有开辟新的栈,也就是拷贝的结果是两个对象指向同一个地址,修改其中一个对象的属性,则另一个对象的属性也会改变,而深拷贝则是开辟新的栈,两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性. 深拷贝的实现方法: b = JSON.parse( JSON.stringify(a) ) 这样做的局限性: 无法复制函数 原型链没了,对象就是object,所属的类没了. 另: jquery.extend()也

js的命名空间 &amp;&amp; 单体模式 &amp;&amp; 变量深拷贝和浅拷贝 &amp;&amp; 页面弹窗设计

说在前面:这是我近期开发或者看书遇到的一些点,觉得还是蛮重要的. 一.为你的 JavaScript 对象提供命名空间 <!DOCTYPE html> <html> <head> <title>为自己的js对象提供命名空间</title> </head> <body> <div>封装自己的数据和函数,防止和其他的库搞混了</div> <script> var jscbObject = {

从一个简单例子来理解js引用类型指针的工作方式

? 1 2 3 4 5 6 7 <script> var a = {n:1};  var b = a;   a.x = a = {n:2};  console.log(a.x);// --> undefined  console.log(b.x);// --> [object Object]  </script> 上面的例子看似简单,但结果并不好了解,很容易把人们给想绕了--"a.x不是指向对象a了么?为啥log(a.x)是undefined?".&

JS 数据类型、赋值、深拷贝和浅拷贝

js 数据类型 六种 基本数据类型: Boolean. 布尔值,true 和 false. null. 一个表明 null 值的特殊关键字. JavaScript 是大小写敏感的,因此 null 与 Null.NULL或其他变量完全不同. undefined. 变量未定义时的属性. Number. 表示数字,例如: 42 或者 3.14159. String. 表示字符串,例如:"Howdy" Symbol ( 在 ECMAScript 6 中新添加的类型)..一种数据类型,它的实例是