相关知识点
1.javascript 变量包含两种不同数据类型的值:基本类型和引用类型。
基本类型值指的是简单的数据段,包括 es6 里面新增的一共是有 6 种,具体如下:number、string、boolean、null、undefined、symbol。
引用类型值指那些可能由多个值构成的对象,只有一种如下:object。在将一个值赋给变量时,解析器必须确定这个值是基本类型值还是引用类型值。
2.javascript 的变量的存储方式:栈(stack)和堆(heap)。
栈:自动分配内存空间,系统自动释放,里面存放的是基本类型的值和引用类型的地址
堆:动态分配的内存,大小不定,也不会自动释放。里面存放引用类型的值。
基本数据类型是按值访问的,因为可以操作保存在变量中的实际的值。引用类型的值是保存在内存中的对象。JavaScript 不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。
基本类型与引用类型最大的区别实际就是 传值与传址 的区别
值传递:基本类型采用的是值传递。地址传递:引用类型则是地址传递,将存放在栈内存中的地址赋值给接收的变量。
浅拷贝
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。即对象的浅拷贝会对“主”对象进行拷贝,但不会复制主对象里面的对象。”里面的对象“会在原来的对象和它的副本之间共享。
基本数据类型 Number(赋值操作)
let a=1;
let b=a;
b //1
b=2;
b //2
a //1
数组
let arr1 = [1,2,3];
let arr2 = arr1;
arr2 //[1,2,3]
arr2.push(4);
arr2 //[1,2,3,4]
arr1 //[1,2,3,4]
首先栈内存 arr1 会指向堆内存里的数组,栈内存的 arr1 保存的是数组的引用,也就相当于内存地址,arr2=arr1, 会把 arr1 的引用赋给 arr2,所以 arr2 也有了数组的引用,此时 arr1 和 arr2 指向的是同一个数组,因此一个数组的改变会影响另一个数组的值。
对象
let obj1={count:1,name:’grace’,age:1};
let obj2 = obj1;
obj2 //{count:1,name:’grace’,age:1}
obj2.count=2;
obj1 //{count:2,name:’grace’,age:1}
obj2 //{count:2,name:’grace’,age:1}
综上所述,如果是基本数据类型,直接进行赋值操作,这样就相当于在栈内存中重新开辟了一个新的空间把值传递过去;如果是引用类型的值传递,进行的就是浅拷贝,浅拷贝赋值的只是对象的引用,如上述 obj2=obj1,实际上传递的只是 obj1 的内存地址,所以 obj2 和 obj1 指向的是同一个内存地址,所以这个内存地址中值的改变对 obj1 和 obj2 都有影响。
深拷贝
深拷贝不仅将原对象的各个属性逐个复制出去,而且将原对象各个属性所包含的对象也依次采用深复制的方法递归复制到新对象上, 所以对一个对象的修改并不会影响另一个对象。
数组
法一:for 循环
let arr1 = [1,2,3];
let arr2 = copyArr(arr1);
function copyArr(arr){
let res=[];
for(let i=0,length=arr.length;i<length;i++){
res.push(arr[i]);
}
return res;
}
法二:slice
用数组自身的方法,slice、concat 方法在运行后会返回新的数组
let arr1 = [1,2,3];
let arr2 = arr1.slice(0);
法三:concat
let arr1 = [1,2,3];
let arr2 = arr1.concat();
法四:扩展运算符
let arr1 = [1,2,3];
let […arr2] = arr1;
法五:Array.from
如果参数是一个真正的数组,Array.from 会返回一个一模一样的新数组
let arr1 = [1,2,3];
let arr2 = Array.from(arr1);
对象
法一:for 循环
let obj1={count:1,name:’grace’,age:1};
let obj2 = copyObj(obj){
let res = {};
for(let key in obj){
res[key]=obj[key];
}
return res;
}
法二:利用 JSON
let obj1={count:1,name:’grace’,age:1};
let obj2 = JSON.parse(JSON.stringify(obj1));
// 使用 JSON 比较简单,但是 JSON 的深拷贝方式会忽略函数对象和原型对象 (有待考证)
法三:扩展运算符
let obj1={count:1,name:’grace’,age:1};
let {…obj2} = obj1;
合成版,可以实现数组和对象的深拷贝
function deepCopy(obj){
let result = Array.isArray(obj)?[]:{};
if(obj && typeof obj === ‘object’){
for(let key in obj){
if(obj.hasOwnProperty(key)){
if(obj[key]&&typeof obj[key]===’object’){
result[key]=deepCopy(obj[key]);
}else{
result[key]=obj[key];
}
}
}
}
return result;
}
注意:ES6 新增了 Object.assign() 方法
第一个参数是目标对象,之后还可以跟一个或多个源对象。它会遍历一个或多个源对象可枚举的自有键并把它们复制到目标对象,最后返回目标对象 assign 是使用 = 操作符来赋值,
Object.assign() 只是一级属性复制,比浅拷贝多深拷贝了一层而已。用的时候,还是要注意这个问题的
作者:优雅 1217 来源:CSDN 原文:https://blog.csdn.net/baidu_3… 版权声明:本文为博主原创文章,转载请附上博文链接!