传值与传址

了解了基本数据类型与引用类型的区别之后,我们就应该能明白传值与传址的区别了。
在我们进行赋值操作的时候,基本数据类型的赋值(=)是在内存中新开辟一段栈内存,然后再把再将值赋值到新的栈中。例如:

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

所以说,基本类型的赋值的两个变量是两个独立相互不影响的变量。

但是引用类型的赋值是传址。只是改变指针的指向,例如,也就是说引用类型的赋值是对象保存在栈中的地址的赋值,这样的话两个变量就指向同一个对象,因此两者之间操作互相有影响。例如:

var a = {}; // a保存了一个空对象的实例
var b = a; // a和b都指向了这个空对象 a.name = 'jozo';
console.log(a.name); // 'jozo'
console.log(b.name); // 'jozo' b.age = 22;
console.log(b.age);// 22
console.log(a.age);// 22 console.log(a == b);// true

浅拷贝

先来看一段代码的执行:

var obj = {a: 1, b: {c: 2}}
var obj1 = obj
var obj2 = shallowCopy(obj);
function shallowCopy(src) {
var dst = {};
for (var prop in src) {
if (src.hasOwnProperty(prop)) {
dst[prop] = src[prop];
}
}
return dst;
} var obj3 = Object.assign({}, obj) obj.a = 2
obj.b.c = 3 console.log(obj) // {a: 2, b: {c: 3}}
console.log(obj1) // {a: 2, b: {c: 3}}
console.log(obj2) // {a: 1, b: {c: 3}}
console.log(obj3) // {a: 1, b: {c: 3}}

这段代码可以说明赋值得到的对象 obj1 只是将指针改变,其引用的仍然是同一个对象,而浅拷贝得到的的 obj2 则是重新创建了新对象。但是,如果原对象obj中存在另一个对象,则不会对对象做另一次拷贝,而是只复制其变量对象的地址。这是因为浅拷贝只复制一层对象的属性,并不包括对象里面的为引用类型的数据。
对于数组,更长见的浅拷贝方法便是slice(0)和 concat()
ES6 比较常见的浅拷贝方法便是 Object.assign

深拷贝

通过上面的这些说明,相信你对深拷贝大致了解了是怎样一个东西了:深拷贝是对对象以及对象的所有子对象进行拷贝。那么如何实现这样一个深拷贝呢?

1. JSON.parse(JSON.stringify(obj))

对于常规的对象,我们可以通过JSON.stringify来讲对象转成一个字符串,然后在用JSON.parse来为其分配另一个存储地址,这样可以解决内存地址指向同一个的问题:

var obj = {a: {b: 1}}
var copy = JSON.parse(JSON.stringify(obj)) obj.a.b = 2
console.log(obj) // {a: {b: 2}}
console.log(copy) // {a: {b: 1}}

但是 JSON.parse()JSON.stringify也存在一个问题,JSON.parse()和J SON.stringify()能正确处理的对象只有Number、String、Array等能够被 json 表示的数据结构,因此函数这种不能被 json 表示的类型将不能被正确处理。

var target = {
a: 1,
b: 2,
hello: function() {
console.log("Hello, world!");
}
};
var copy = JSON.parse(JSON.stringify(target));
console.log(copy); // {a: 1, b: 2}
console.log(JSON.stringify(target)); // "{"a":1,"b":2}"

2. 遍历实现属性复制

既然浅拷贝只能实现非object第一层属性的复制,那么遇到object只需要通过递归实现浅拷贝其中内部的属性即可:

function extend (source) {
var target
if (typeof source === 'object') {
target = Array.isArray(source) ? [] : {}
for (var key in source) {
if (source.hasOwnProperty(key)) {
if (typeof source[key] !== 'object') {
target[key] = source[key]
} else {
target[key] = extend(source[key])
}
}
}
} else {
target = source
}
return target
} var obj1 = {a: {b: 1}}
var cpObj1 = extend(obj1)
obj1.a.b = 2
console.log(cpObj1) // {a: {b: 1}} var obj2 = [[1]]
var cpObj2 = extend(obj2)
obj2[0][0] = 2
console.log(cpObj2) // [[1]]

我们再来看一下 Zepto 中深拷贝的代码:

    // 内部方法:用户合并一个或多个对象到第一个对象
// 参数:
// target 目标对象 对象都合并到target里
// source 合并对象
// deep 是否执行深度合并
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] 不是数组,则 target[key] = [] 初始化一下,否则递归会出错的
if (isArray(source[key]) && !isArray(target[key]))
target[key] = []
// 执行递归
extend(target[key], source[key], deep)
}
// 不满足以上条件,说明 source[key] 是一般的值类型,直接赋值给 target 就是了
else if (source[key] !== undefined) target[key] = source[key]
}

内部实现其实也是差不多。

js 浅拷贝和深拷贝的更多相关文章

  1. 理解js浅拷贝和深拷贝

    理解深拷贝和浅拷贝之前先了解下js中的基本类型和引用类型 1.基本类型: 在js中,数据的基本类型undefined,null,string,number,boolean,在变量中赋的实际值,基本类型 ...

  2. 关于js浅拷贝与深拷贝的理解

    前端开发中,一般情况下,很少会去在意深拷贝与浅拷贝的关系. 大家知道,js变量有2种数据类型:基本类型和引用类型.基本类型的拷贝是将整个值完全拷贝一份的,也就是深拷贝.就是开辟了新的堆内存.所以基本类 ...

  3. 关于JS浅拷贝和深拷贝

    在 JS 中有一些基本类型像是Number.String.Boolean,而对象就是像这样的东西{ name: 'Larry', skill: 'Node.js' },对象跟基本类型最大的不同就在于他 ...

  4. JS - 浅拷贝与深拷贝的理解以及简单实现方法

    前几天撸项目代码时, 由一个技术点间接牵扯出了这东西. 所以就来总结一下. 深拷贝 拷贝对象每个层级的属性. 作用的对象是 js中引用类型的对象,基本类型没有涉及. 本质上将引用类型的对象在堆上重新开 ...

  5. JS对象复制(深拷贝、浅拷贝)

    如何在 JS 中复制对象 在本文中,我们将从浅拷贝(shallow copy)和深拷贝(deep copy)两个方面,介绍多种 JS 中复制对象的方法. 在开始之前,有一些基础知识值得一提:Javas ...

  6. JS 对象的深拷贝和浅拷贝

    转载于原文:https://www.cnblogs.com/dabingqi/p/8502932.html 这篇文章是转载于上面的链接地址,觉得写的非常好,所以收藏了,感谢原创作者的分享. 浅拷贝和深 ...

  7. JS中的引用、浅拷贝和深拷贝

    js的深拷贝浅拷贝是很常遇到的问题,一直模模糊糊有点说不过去,所以这次好好总结一下. 1.js的引用 JS分为基础类型和引用类型两种数据类型: 基础类型:number.string.boolean.n ...

  8. js对象浅拷贝和深拷贝详解

    js对象浅拷贝和深拷贝详解 作者:i10630226 字体:[增加 减小] 类型:转载 时间:2016-09-05我要评论 这篇文章主要为大家详细介绍了JavaScript对象的浅拷贝和深拷贝代码,具 ...

  9. js对象的直接赋值、浅拷贝与深拷贝

    最近Vue项目中写到一个业务,就是需要把对话框的表单中的数据,每次点击提交之后,就存进一个el-table表格中,待多次需要的表单数据都提交进表格之后,再将这个表格提交,实现多个表单数据的同时提交,期 ...

随机推荐

  1. 用adb命令组装PowerShell实用小工具——Android测试小助手

    [本文出自天外归云的博客园] 简介 APP性能测试一般对以下几个方面进行测试: 1.启动时间(可以通过本工具测试): 2.CPU的占用(可以通过本工具测试): 3.内存的占用(可以通过本工具测试): ...

  2. KVM虚拟机的xml配置文件

    在RHEL6中,用于从磁盘启动的XML文件 这里以dcs01.xml为例: <domain type='kvm'><name>dcs01</name><uui ...

  3. Redis面试题及分布式集群

    Reference: http://blog.csdn.net/yajlv/article/details/73467865 1. 使用Redis有哪些好处? (1) 速度快,因为数据存在内存中,类似 ...

  4. JavaScript高级 面向对象(11)--对象的动态特性-关联数组用法

    说明(2017.4.2): 1. 对象的动态特性: (1)在js中,一个对象需要属性,就可以利用“对象名.属性 = 值”的方式为其添加,只要赋值成功,对象就新增这个属性. (2)对象属性的访问形式: ...

  5. .net 微信Token验证

    首次接受这个项目,看了微信的API,云里雾里,经过几经测试,理清思路 开发者自个申请,微信API给出四个参数: 下面我解释下 signature 是微信加密签名 即:微信服务器将 timetamp n ...

  6. Struts标签判断当前用户是否存在

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  7. php数组转xml

    0x00 需求 最近要做百度.360.神马搜索的网站sitemap,三家的格式都是xml,然而具体的细节还有有差别的. 一开始用的是dom,没有使用sax,写了几段便觉得太傻了,想到有没有数组转xml ...

  8. Maven 解决 下载项目 compiler 为1.5的问题

    在 开发Maven 项目的时候,会发现个问题,就是下载下来的项目默认 compiler 为1.5 ,项目报错. 明明之前开发用的是1.7的啊. 这里只需要在pom.xml确定下就好了. <pro ...

  9. 【微信小程序】下拉刷新真机测试无效

    根据文档的描述,做上拉加载时直接实现页面的onReachBottom()函数即可.但是要做下拉刷新时,除了实现onPullDownRefresh()函数外,还必须要在app.json中配置开启enab ...

  10. 在 Linux 下用 grep 时高亮显示匹配的部分

    用 grep 匹配文件时,显示结果黑压压的一片执行一下这条命令,重新 grep 试试看export GREP_OPTIONS='--color=auto'好看多了,不是吗?你可以把 export GR ...