从JS的深拷贝与浅拷贝到jq的$.extend()方法

一、堆内存与栈内存

  堆和栈都是内存中划分出来的用来存储的区域,栈为自动分配的内存空间,它由系统自动释放,堆为动态分配的内存,大小不定也不会自动释放。

二、js基本数据类型与引用类型的不同

基本数据类型(boolean,undefined,null,string,number)

  1.基本数据类型存放在栈内存中

  是存放在栈中的简单数据段,数据大小确定,内存空间大小可以分配,是直接按值存放的,所以可以直接访问。

  2、基本数据类型值不可变

    js中给基本类型赋值或操作基本类型数据时,并没有改变基本类型的原始值,数字和布尔类型的值显然是不可变的,字符串虽然有很多方法去操作,但都是在创造一个新的字符串,它的原始值并没有改变。

  3、基本数据类型的比较是值的比较

  只要他们的值是相等的就认为他们是相等的。

var a = 1;
var b = 1;
console.log(a == b);//true

这里最好用严格等,否则会进行类型转换;

var a = 0;
var b = ‘0‘;
console.log(a == b);//true
console.log(a === b); //false

引用类型(数组】、对象、函数)

1、引用类型存放在堆内存

2、引用类型值可变

3、引用类型的比较是引用的比较

var a = [1,2,3];
var b = [1,2,3];
console.log(a === b);//false

比较两个对象的引用,是看两个引用是否指向同一个对象

基本数据类型与引用类型赋值比较

基本数据类型赋值是值的传递,先在栈内存中开辟一段内存,再把值赋值到新的栈中

var a = 10;
var b = a;

a ++ ;
console.log(a); // 11
console.log(b); // 10

引用类型的赋值是传址,就是说赋值时是保存在栈中的变量的地址的赋值,这样两个变量指向同一个对象,所以两个变量之间会相互影响;

var a = {};
var b = a;
a.name = "qy";
console.log(a.name);//qy
console.log(b.name);//qy
b.age = 22;
console.log(a.age);//22
console.log(b.age);//22console.log(a === b);//true

赋值并不是浅拷贝,赋值和浅拷贝之间的区别

var obj1 = { //原始数据
  "name" : "zhangsan",
  "age" : "22",
  "language" : [1, [2, 3], [4, 5]]
}
var obj2 = obj1;//赋值得到
var obj3 = shallowCopy(obj1);//浅拷贝得到
function shallowCopy(src) {
   var dst = {};
   for (var prop in src) {
       if (src.hasOwnProperty(prop)) {
           dst[prop] = src[prop];
       }
   }
   return dst;
}
obj2.name = "lisi";//改变赋值得到的obj2的基本类型属性name,最后结果为原始数据里的属性也随之改变
obj3.age = "11";//改变浅拷贝得到的obj3的基本类型属性age,结果为原始数据的age属性并没有改变
obj2.language[1] = [‘a‘, ‘b‘];//改变赋值得到的obj2的引用类型属性,结果为原始数据及由原始数据浅拷贝得到的obj3的language属性均被改变
obj3.language[2] = [‘c‘, ‘d‘];//改变浅拷贝得到的obj3的引用类型属性,结果为原始数据及有原始数据赋值得到的obj2的language属性均被改变
console.log(obj1);//name:lisi,age:22,language:[1,[a,b],[c,d]]
console.log(obj2);//name:lisi,age:22,language:[1,[a,b],[c,d]]
console.log(obj3);//name:zhangsan,age:11,language:[1,[a,b],[c,d]]

结论:(首先需要明确深拷贝与浅拷贝都是针对引用类型而言的,基本数据类型不涉及到深拷贝与浅拷贝)

@1 引用类型的赋值是地址的传递,即赋值得到的新数据与原数据指向堆内存中的同一个对象,两者之间仍会互相影响;

@2 浅拷贝是通过创建一个新的对象(数组,对象),依次去拷贝对象的每一个属性,此时如果对象的属性为一个引用类型,那么拷贝过来的引用类型属性依然是指向与原数据的引用类型属性地址相同的一个对象,因此通过浅拷贝得到的新数据,与原数据的引用类型属性会相互影响;

@3 那么深拷贝是怎样的呢,深拷贝就是要做到新数据与原数据完全的互不影响(无论是基本类型还是引用类型);

三、如何进行深拷贝?

思路:递归调用浅拷贝方法,拷贝每一层次的对象属性;以下为zepto的extend方法

$.extend = function(target) {
            var deep,
                args = slice.call(arguments, 1);
            if (typeof target == ‘boolean‘) {
                deep = target;
                //target取第二个参数
                target = args.shift();
            }
            //遍历后面的参数,都合并到target上面
            args.forEach(function(arg){
                extend(target, arg, deep)
            })
            return target;
        }
        function extend(target, source, deep) {
            for (key in source) {
                //是深拷贝且为数组或者对象时
                if (deep && (isPlainObject(source[key]) || isArray(source[key]))) {
                    //source[key]是对象,而target[key]不是对象,则target[key]初始化一下,否则递归出错
                    if (isPlainObject(source[key]) && isPlainObject(target[key])) {
                        target[key] = {};
                    }
                    //source[key]是数组,而target[key]不是数组也要初始化一下
                    if (isArray(source[key]) && !isArray(target[key])) {
                        target[key] = [];
                    }
                    //执行递归
                    extend(target[key], source[key], deep);
                } else if (target[key] !== undefined) {
                    target[key] = source[key];
                }

            }
        }

 四、$.extend()方法(jquery的extend扩展方法)

1、原型:extend(dest,src1,src2,src3...);

含义:将src1,src2,src3...合并到dest中,返回值为合并后的dest

2、dest可为{}

var newSrc=$.extend({},src1,src2,src3...)//也就是将"{}"作为dest参数。

含义: 这样就可以将src1,src2,src3...进行合并,然后将合并结果返回给newSrc了;

例:

var result=$.extend({},{name:"Tom",age:21},{name:"Jerry",sex:"Boy"})
//结果为:
result={name:"Jerry",age:21,sex:"Boy"}

可见此方法中后面的参数如果和前面的参数存在相同的名称,那么后面的会覆盖前面的参数值。

3.重载原型1:省略dest参数,则该方法就只能有一个src参数,而且是将该src合并到调用extend方法的对象中去

例:

$.extend({
hello:function(){alert(‘hello‘);}
});
//将hello方法合并到jquery的全局对象中去

4、重载原型2extend(boolean,dest,src1,src2,src3...)

含义:第一个参数boolean代表是否进行深度拷贝,其他参数同上;

var result = $.extend(true,{}, {name: "a", location:{city: "beijing", pos: 1000}}, {age: 12, location:{city: "hanguo", age: 20}})

result={name: "a", age: 12, location: {city: "hanguo", pos: 1000, age: 20}};

var result = $.extend(false, {}, {name: "a", location:{city: "beijing", pos: 1000}}, {age: 12, location:{city: "hanguo", age: 20}});

result= {name: "a", age: 12, location: {city: "hanguo", age: 20}}}

原文地址:https://www.cnblogs.com/youyang-2018/p/9141536.html

时间: 2024-08-02 19:39:56

从JS的深拷贝与浅拷贝到jq的$.extend()方法的相关文章

【JS】深拷贝与浅拷贝的区别,实现深拷贝的几种方法

如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果A没变,那就是深拷贝,自食其力. 此篇文章中也会简单阐述到栈堆,基本数据类型与引用数据类型,因为这些概念能更好的让你理解深拷贝与浅拷贝. 我们来举个浅拷贝例子: let a=[0,1,2,3,4], b=a; console.log(a===b); a[0]=1; console.log(a,b); 嗯?明明b复制了a,为啥修改数组a,数组b也跟着变了,这里我不

JS中深拷贝与浅拷贝的区别,实现深拷贝的几种方法

JS中深拷贝与浅拷贝的区别,实现深拷贝的几种方法 如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力. 此篇文章中也会简单阐述到栈堆,基本数据类型与引用数据类型,因为这些概念能更好的让你理解深拷贝与浅拷贝. 我们来举个浅拷贝例子: let a=[0,1,2,3,4], b=a; console.log(a===b); a[0]=1; console.log(a,b); 嗯?明明b复

JS JavaScript深拷贝、浅拷贝

浅拷贝:浅拷贝只是复制了内存地址,如果原地址中的对象改变了,浅复制出来的对象也会相应改变. 深拷贝:开辟了一块新的内存存放地址和地址指向的对象. 深拷贝数组(只拷贝第一级数组): 1.直接遍历 var arr = [1,2,3,4]; function copy(arg){ var newArr = []; for(var i = 0; i < arr.length; i++) { newArr.push(arr[i]); } return newArr; } var newArry = cop

浅谈深拷贝和浅拷贝及几种实现方法

讨论深拷贝与浅拷贝之前,要先回顾一下值传递与引用传递: 值传递: var a = 10; var b = a; b++; //console.log(a,b)//a:10 b:11 引用传递: var arr = [10,20,30,40]; var arr1 = arr; arr1[0] = 40; //console.log(arr,arr1);//[40,20,30,40] [40,20,30,40] 一.浅拷贝(引用传递) (1)概念 浅拷贝: 当一个对象拷贝另一个对象的数据的时候,只要

JS中深拷贝和浅拷贝记录及解决方法

这是本人第一次写博客...好紧张,有什么固定格式麽,需要爆照麽..怎样才能让自己表现的不是第一次啊.. 不多说,最近一不小心就跳入一个坑,也是怪我自己知识点扩展不够..这次记录下,上代码 /*a 原来的数组* b 复制后的新数组* */function copy(a,b) { for(var i=0;i<a.length;i++) { b.push(a[i]) }}var arr1=[1,2,3,4,5];var arr2=[];copy(arr1,arr2);console.log(arr2)

js的深拷贝和浅拷贝

一.数组的深浅拷贝 在使用JavaScript对数组进行操作的时候,我们经常需要将数组进行备份,事实证明如果只是简单的将它赋予其他变量,那么我们只要更改其中的任何一个,然后其他的也会跟着改变,这就导致了问题的发生. var arr = ["One","Two","Three"]; var arrto = arr; arrto[1] = "test"; document.writeln("数组的原始值:" +

js之深拷贝、浅拷贝

浅拷贝 对于基本类型,浅拷贝是对值的复制,对于对象来说,浅拷贝只复制指向某个对象的指针,而不复制对象本身,并没有开辟新的栈,也就是复制的结果是新旧对象还是共享同一块内存,两个对象指向同一个地址,修改其中一个对象的属性,则另一个对象的属性也会改变. 深拷贝 深拷贝会开辟新的栈,创造一个一模一样的对象,两个对象对应两个不同的地址,不共享内存,修改一个对象的属性,不会改变另一个对象的属性. 基本类型 和 对象类型 他们最大的区别就是在于他们的传值方式. 基本类型是传值 对象类型就是传引用. <scri

JS中深拷贝数组、对象、对象数组方法

我们在JS程序中需要进行频繁的变量赋值运算,对于字符串.布尔值等可直接使用赋值运算符 "=" 即可,但是对于数组.对象.对象数组的拷贝,我们需要理解更多的内容. 首先,我们需要了解JS的浅拷贝与深拷贝的区别. 我们先给出一个数组: var arr = ["a","b"]; 现在怎么创建一份arr数组的拷贝呢?直接执行赋值运算吗?我们来看看输出结果 var arrCopy = arr; arrCopy[1] = "c"; arr

4个方面彻底说清JS的深拷贝/浅拷贝

首先,本文适用于业务需要,急需知道如何深拷贝JS对象的开发者.第二类,希望扎实JS基础,将来好去面试官前秀操作的好学者. 第一类 你只需要一行黑科技代码就可以实现深拷贝 var copyObj = { name: 'ziwei', arr : [1,2,3] } var targetObj = JSON.parse(JSON.stringify(copyObj)) 此时 copyObj.arr !== targetObj.arr 已经实现了深拷贝 别着急走,利用window.JSON的方法做深拷