JS基本类型-引用类型-深浅拷贝
在JavaScript中变量包含两种类型的值:一种是基本类型,一种是引用类型。
基本类型包括:数值、字符串、null、undefined、布尔值
引用类型包括:对象、数组、函数、正则…
补充: null和undefined的区别
null表示"没有对象",即该处不应该有值。
典型用法是:
(1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。
undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。
典型用法是:
(1)变量被声明了,但没有赋值时,就等于undefined。
(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。
(3)对象没有赋值的属性,该属性的值为undefined。
(4)函数没有返回值时,默认返回undefined。
1.引用类型的动态属性
对于引用类型的值,我们可以为其添加属性和方法,也可以改变或删除属性和方法,
对于基本类型的值,尽管给其添加属性和方法不会报错,但这是无效的。
var obj=new Object();
obj.name="zuobaiquan";
var str="zbq";
str.age=20;
console.log(obj.name);// zuobaiquan
console.log(str.age);// undefined
2.基本类型值和引用类型值的复制
2.1基本类型值
基本类型值是指在栈内存保存的简单数据段,在复制基本类型值的时候,会开辟出一个新的内存空间,将值复制到新的内存空间。
var a = 1;
var b = a;
a = 2;
console.log(a);//输出2;
console.log(b);//输出1;
var a = 1;
var b = a;
a = 2;
从上面例子看出,当一个变量的值是基本类型,把它复制给另一个变量,复制完成后改变它的值,不会影响已经复制了它的值的变量。
2.1引用类型值
引用类型值是保存在堆内存中的对象,变量保存的只是指向该内存的地址,在复制引用类型值的时候,其实只复制了指向该内存的地址。
var a = {
name: 'Kitty',
age: '20',
sex: 'man'
};
var b = a;
a.name = 'Jack';
console.log(a);//输出{name: 'Jack',age: 20,sex: 'man'}
console.log(b);//输出{name: 'Jack',age: 20,sex: 'man'}
var a = {name: ‘Kitty’,age: ‘20’,sex: ‘man’};
var b = a;
a.name = ‘Jack’;
从上面例子看出,当一个变量的值是引用类型值,把它复制给另外一个变量,复制的只是指向储存对象内存的地址,所以复制完成后,改变它的值,会影响复制了它的值的变量。
注意:如果有两个变量的值是引用类型值,就算它们的值完全相同,它们也是不相等的,因为它们指向的内存地址不同,例子:
3.对象的浅拷贝和深拷贝
当一个变量是对象,如果像上面那样直接将一个变量赋值给另一个变量,如果改变某个变量的值,另外一个变量也会跟着改变,如果我们不想发生这种情况,就需要写一个函数用来拷贝对象。
3.1浅拷贝
当对象里的属性的值只有基本类型的值时候。
var a = {
name: 'Kitty',
age: 12,
sex: 'man'
}
function copy(obj){
var newObj = {};
for(vl in obj){
newObj[vl] = obj[vl]
}
return newObj;
}
例子:
从上面例子看到,我们通过这种方式拷贝对象,改变某个变量的值,并不会影响另一个变量。
3.1深拷贝
当对象里的属性的值还是一个对象,这时候用上面的方法就不行了,例子:
这时候要改进这个函数:
使用递归的方法:
function deepCopy(obj){
var newObj = {};
for(vl in obj){
if(typeof obj[vl] === 'object' && obj[vl] !== null){
newObj[vl] = deepCopy(obj[vl]);
}else{
newObj[vl] = obj[vl];
}
}
return newObj;
}
例子:
使用JSON的方法:
JSON.stringify(),将一个对象解析成字符串。
JSON.parse(),从一个字符串中解析出json 对象。
我们可以使用上面两个个方法来进行对象的深拷贝:
JSON.parse(JSON.stringify());
例子:
JSON.parse(JSON.stringify(obj)) 实现深拷贝的一些坑
1.如果json里面有时间对象,则序列化结果:时间对象=>字符串的形式;
let obj = {
age: 18,
date: new Date()
};
let objCopy = JSON.parse(JSON.stringify(obj));
console.log('obj', obj); // {age: 18, date: Thu Mar 12 2020 15:39:35 GMT+0800 (中国标准时间)}
console.log('objCopy', objCopy); //{age: 18, date: "2020-03-12T07:39:35.372Z"}
2.如果json里有RegExp、Error对象,则序列化的结果将只得到空对象 RegExp、Error => {};
let obj = {
age: 18,
reg: new RegExp('\\w+'),
err: new Error('error message')
};
let objCopy = JSON.parse(JSON.stringify(obj));
console.log('obj', obj); //{age: 18, reg: /\w+/, err: Error: error message
at <anonymous>:4:10}
console.log('objCopy', objCopy); // {age: 18, reg: {…}, err: {…}}
3.如果json里有 function,undefined,则序列化的结果会把 function,undefined 丢失
let obj = {
age: 18,
fn: function () {
console.log('fn');
},
hh: undefined
};
let objCopy = JSON.parse(JSON.stringify(obj));
console.log('obj', obj); //{age: 18, hh: undefined, fn: ƒ}
console.log('objCopy', objCopy); //{age: 18}
4.如果json里有NaN、Infinity和-Infinity,则序列化的结果会变成null;
let obj = {
age: 18,
hh: NaN,
isInfinite: 1.7976931348623157E+10308,
minusInfinity: -1.7976931348623157E+10308
};
let objCopy = JSON.parse(JSON.stringify(obj));
console.log('obj', obj); //{age: 18, hh: NaN, isInfinite: Infinity, minusInfinity: -Infinity}
console.log('objCopy', objCopy); //{age: 18, hh: null, isInfinite: null, minusInfinity: null}
5.如果json里有对象是由构造函数生成的,则序列化的结果会丢弃对象的 constructor;
6.如果对象中存在循环引用的情况也无法实现深拷贝
来源:https://segmentfault.com/a/1190000020297508
如何拷贝数组呢
拷贝一个数组但是对副本的修改不影响原来的数组
//方法1
var a = [1,2,3];
var b = a.slice(0);
a.reverse();
console.log(a);//[3,2,1]
console.log(b);//[1,2,3] //方法2
var c = [4,5,6];
var d = c.concat();
c.reverse();
console.log(c);//[6,5,4]
console.log(d);//[4,5,6] //方法3
var arr = [1,2,3,4,5]
var [ ...arr2 ] = arr
arr[2] = 5
console.log(arr)
console.log(arr2) //方法4
var arr = [1,2,3,4,5]
var arr2 = copyArr(arr)
function copyArr(arr) {
let res = []
for (let i = 0; i < arr.length; i++) {
res.push(arr[i])
}
return res
}
JS基本类型-引用类型-深浅拷贝的更多相关文章
- JS对象和数组深浅拷贝总结②
在实际开发中遇到过太多次深拷贝浅拷贝的问题.总结一下~ JS数据存储和深浅拷贝实际运用① 这是之前写过的一篇文章,解决浅拷贝深拷贝的问题只说了一种方法,今天来补充一下. 介绍深拷贝和浅拷贝都在上一篇文 ...
- js 基本类型&引用类型
1.基本的数据类型有:undefined,boolean,number,string,null.基本类型的访问是按值访问的,就是说你可以操作保存在变量中的实际的值 基本类型的比较是值的比较.用==比较 ...
- js基本类型 引用类型
参考 https://segmentfault.com/a/1190000005794070 http://blog.csdn.net/yummy_go/article/details/5050468 ...
- JS的赋值与深浅拷贝实例
赋值 基本类型: 传值,在栈内存中的数据发生数据变化的时候,系统会自动为新的变量分配一个新的之值在栈内存中,两个变量相互独立,互不影响的 引用类型: 传址,只改变指针的指向,指向同一个对象,两个变量相 ...
- .NET的堆和栈03,引用类型对象拷贝以及内存分配
在" .NET的堆和栈01,基本概念.值类型内存分配"中,了解了"堆"和"栈"的基本概念,以及值类型的内存分配.我们知道:当执行一个方法的时 ...
- js 基础数据类型和引用类型 ,深浅拷贝问题,以及内存分配问题
js 深浅拷贝问题 浅拷贝一般指的是基本类型的复制 深拷贝一般指引用类型的拷贝,把引用类型的值也拷贝出来 举例 h5的sessionStorage只能存放字符串,所以要存储json时就要把json使用 ...
- 【 js 基础 】 深浅拷贝
underscore的源码中,有很多地方用到了 Array.prototype.slice() 方法,但是并没有传参,实际上只是为了返回数组的副本,例如 underscore 中 clone 的方法: ...
- 【 js 基础 】【 源码学习 】 深浅拷贝
underscore的源码中,有很多地方用到了 Array.prototype.slice() 方法,但是并没有传参,实际上只是为了返回数组的副本,例如 underscore 中 clone 的方法: ...
- JS中深浅拷贝 函数封装代码
一.了解 基本数据类型保存在栈内存中,按值访问,引用数据类型保存在堆内存中,按址访问. 二.浅拷贝 浅拷贝只是复制了指向某个对象的指针,而不是复制对象本身,新旧对象其实是同一内存地址的数据,修改其中一 ...
随机推荐
- ocrosoft 1015 习题1.22 求一元二次方程a*x^2 + b*x + c = 0的根
http://acm.ocrosoft.com/problem.php?id=1015 题目描述 求一元二次方程a*x2 + b*x + c = 0的根.系数a.b.c为浮点数,其值在运行时由键盘输入 ...
- TortoiseGit push免输密码
(ฅ>ω<*ฅ) 噫又好了~ TortoiseGit push免输密码的方法 – 晨旭的博客~https://www.chenxublog.com/2016/03/04/tortoiseg ...
- PHP之CLI模式
转载: http://www.cnblogs.com/zcy_soft/archive/2011/12/10/2283437.html 所有的PHP发行版,不论是编译自源代码的版本还是预创建的版本,都 ...
- Git命令以及常见注意事项
命令: git init -> 初始化一个git仓库 git clone -> 克隆一个本地库 git pull -> 拉取服务器最新代码 git fetch –p -> 强行 ...
- Tomcat 目录结构以及基本配置
1 Tomcat 目录层次结构 ① bin:存放启动和关闭tomcat 的脚本文件② conf: 存放配置文件 server.xml:该文件用于配置和server 相关的信息,比如tomcat 启动端 ...
- [转帖]Linux分页机制之概述--Linux内存管理(六)
Linux分页机制之概述--Linux内存管理(六) 2016年09月01日 19:46:08 JeanCheng 阅读数:5491 标签: linuxkernel内存管理分页架构更多 个人分类: ┈ ...
- CLOUD物料列表查询的一份跟踪
SELECT * FROM (SELECT t0.FNUMBER fnumber, t0_L.FNAME fname, t0_L.FSPECIFICATION fspecification, t0.F ...
- 介绍Ajax与jQuery技术
Ajxs技术(异步的JavaScript与XML)已有多种技术的组合 Ajax的优点是什么? 1.可以实现客户端的异步请求操作2.进而在不需要刷新页面的情况下与服务器进行通信,减少用户的等待时间3.减 ...
- Linux基础学习(13)--Linux系统管理
第十三章——Linux系统管理 一.进程管理 1.进程查看: (1)进程简介:进程是正在执行的一个程序或命令,每一个进程都是一个运行的实体,都有自己的地址空间,并占用一定的系统资源. (2)进程管理的 ...
- final关键字的用法
final关键字的作用 1.被final修饰的类不能被继承 报错信息:cannot inherit from final 'com.dajia.test.Animal' 2.被final修饰的方法不能 ...