【 js 基础 】【 源码学习 】 深浅拷贝
// Create a (shallow-cloned) duplicate of an object.
// 对象的 `浅复制` 副本
// 注意点:所有嵌套的对象或者数组都会跟原对象用同一个引用
// 所以是为浅复制,而不是深度克隆
_.clone = function(obj) {
// 容错,如果不是对象或者数组类型,则可以直接返回
// 因为一些基础类型是直接按值传递的
if (!_.isObject(obj))
return obj; // 如果是数组,则用 obj.slice() 返回数组副本
// 如果是对象,则提取所有 obj 的键值对覆盖空对象,返回
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};
var a = ["a","b","c"];
var a_copy = a;
console.log(a === a_slice);
a_slice[0]="f";
console.log(a_slice);
console.log(a);
var obj = {name:"xixi",age:20};
var obj_extend = $.extend(true,{}, obj); //extend方法,第一个参数为true,为深拷贝,为false,或者没有为浅拷贝。
console.log(obj === obj_extend);
obj.name = "heihei";
console.log(obj);
console.log(obj_extend);
- 基本类型:undefined,null,布尔值(Boolean),字符串(String),数值(Number)
- 引用类型: 统称为Object类型,细分的话,有:Object类型,Array类型,Date类型,Function类型等。

即
var a = “A”;
在栈内存中是这样的

即
var a = {name:“jack”};
在内存中是这样的
3、不同类型的复制方式:
var a = 1;
var b = a;
console.log(a === b);
var a = 2;
console.log(a);
console.log(b);
改变 a 变量的值,并不会影响 b 的值。
内存中是这样的:
var a = 1;
var b = a;
a = 2;
var a = {name:”jack",age:20};
var b = a;
console.log(a === b);
a.age = 30;
console.log(a);
console.log(b);
改变 a 变量的值,会影响 b 的值。
内存中是这样的:
var a = {name:“jack",age:20};
var b = a;
a.age = 30;
深浅拷贝 的主要区别就是:复制的是引用(地址)还是复制的是实例。
所以上面的栗子2,如何可以变成深拷贝呢?
我们可以想象出让 b 在内存中像下图这样,肯定就是深拷贝了。
那么代码上如何实现呢?
利用 递归 来实现深复制,对属性中所有引用类型的值,遍历到是基本类型的值为止。
function deepClone(source){
if(!source && typeof source !== 'object'){
throw new Error('error arguments', 'shallowClone');
}
var targetObj = source.constructor === Array ? [] : {};
for(var keys in source){
if(source.hasOwnProperty(keys)){
if(source[keys] && typeof source[keys] === 'object'){
targetObj[keys] = source[keys].constructor === Array ? [] : {};
targetObj[keys] = deepClone(source[keys]); //递归
}else{
targetObj[keys] = source[keys];
}
}
}
return targetObj;
}
检测一下
var a = {name:"jack",age:20};
var b = deepClone(a);
console.log(a === b);
a.age = 30;
console.log(a);
console.log(b);
三 、最后让我们来看看 一些 js 中的 复制方法,他们到底是深拷贝还是浅拷贝?
1、 Array 的 slice 和 concat 方法
两者都会返回一个新的数组实例。
栗子
var a = [1,2,3];
var b = a.slice(); //slice
console.log(b === a);
a[0] = 4;
console.log(a);
console.log(b);
var a = [1,2,3];
var b = a.concat(); //concat
console.log(b === a);
a[0] = 4;
console.log(a);
console.log(b);
看到结果,如果你觉得,这两个方法是深复制,那就恭喜你跳进了坑里
让咱们再看一个颠覆你观念的栗子:
var a = [[1,2,3],4,5];
var b = a.slice();
console.log(a === b);
a[0][0] = 6;
console.log(a);
console.log(b);
var obj = {name:'xixi',age:20,company : { name : '腾讯', address : '深圳'} };
var obj_extend = $.extend(true,{}, obj); //extend方法,第一个参数为true,为深拷贝,为false,或者没有为浅拷贝。
console.log(obj === obj_extend);
obj.company.name = "ali";
obj.name = "hei";
console.log(obj);
console.log(obj_extend);
浅拷贝:
var obj = {name:"xixi",age:20};
var obj_extend = $.extend(false,{}, obj); //extend方法,第一个参数为true,为深拷贝,为false,或者没有为浅拷贝。
console.log(obj === obj_extend);
obj.name = "heihei";
console.log(obj);
console.log(obj_extend);
咦,company 的变化 可以看出 深浅复制来(即箭头所指), 红色方框圈出的地方,怎么和上面 slice 和 concat 的情况一样?难道也是羊?
var obj = {name:'xixi',age:20,company : { name : '腾讯', address : '深圳'} };
var obj_json = JSON.parse(JSON.stringify(obj));
console.log(obj === obj_json);
obj.company.name = "ali";
obj.name = "hei";
console.log(obj);
console.log(obj_json);
完全的 深拷贝。

【 js 基础 】【 源码学习 】 深浅拷贝的更多相关文章
- Vue.js 源码学习笔记
最近饶有兴致的又把最新版 Vue.js 的源码学习了一下,觉得真心不错,个人觉得 Vue.js 的代码非常之优雅而且精辟,作者本身可能无 (bu) 意 (xie) 提及这些.那么,就让我来吧:) 程序 ...
- 【目录】Spring 源码学习
[目录]Spring 源码学习 jwfy 关注 2018.01.31 19:57* 字数 896 阅读 152评论 0喜欢 9 用来记录自己学习spring源码的一些心得和体会以及相关功能的实现原理, ...
- 【 js 基础 】【 源码学习 】源码设计 (持续更新)
学习源码,除了学习对一些方法的更加聪明的代码实现,同时也要学习源码的设计,把握整体的架构.(推荐对源码有一定熟悉了之后,再看这篇文章) 目录结构:第一部分:zepto 设计分析第二部分:undersc ...
- 【 js 基础 】【 源码学习 】backbone 源码阅读(一)
最近看完了 backbone.js 的源码,这里对于源码的细节就不再赘述了,大家可以 star 我的源码阅读项目(https://github.com/JiayiLi/source-code-stud ...
- 【 js 基础 】【 源码学习 】backbone 源码阅读(二)
最近看完了 backbone.js 的源码,这里对于源码的细节就不再赘述了,大家可以 star 我的源码阅读项目(source-code-study)进行参考交流,有详细的源码注释,以及知识总结,同时 ...
- 【 js 基础 】【 源码学习 】backbone 源码阅读(三)浅谈 REST 和 CRUD
最近看完了 backbone.js 的源码,这里对于源码的细节就不再赘述了,大家可以 star 我的源码阅读项目(https://github.com/JiayiLi/source-code-stud ...
- 【 js 基础 】【 源码学习 】backbone 源码阅读(三)
最近看完了 backbone.js 的源码,这里对于源码的细节就不再赘述了,大家可以 star 我的源码阅读项目(https://github.com/JiayiLi/source-code-stud ...
- 【 js 基础 】【 源码学习 】源码设计 (更新了backbone分析)
学习源码,除了学习对一些方法的更加聪明的代码实现,同时也要学习源码的设计,把握整体的架构.(推荐对源码有一定熟悉了之后,再看这篇文章) 目录结构:第一部分:zepto 设计分析 第二部分:unders ...
- Underscore.js 源码学习笔记(下)
上接 Underscore.js 源码学习笔记(上) === 756 行开始 函数部分. var executeBound = function(sourceFunc, boundFunc, cont ...
- Underscore.js 源码学习笔记(上)
版本 Underscore.js 1.9.1 一共 1693 行.注释我就删了,太长了… 整体是一个 (function() {...}()); 这样的东西,我们应该知道这是一个 IIFE(立即执行 ...
随机推荐
- SpringBoot入门之内嵌Tomcat配置
spring boot默认web程序启用tomcat内嵌容器tomcat,监听8080端口,servletPath默认为 / .需要用到的就是端口.上下文路径的修改,在spring boot中其修改方 ...
- javascript window对象属性和方法
window对象 window对象表示一个浏览器窗口或一个框架.在客户端JavaScript中,window对象是全局对象,所有的表达式 都在当前的环境中计算.也就是说,要引用当前窗口根本不需要特殊的 ...
- 怎么把excel表格内的数据导入数据库?
第一种方法: 思路:想要把excel表格内的数据直接导入数据库不是那么容易,可以把excel表格另存为.csv格式的文档(特点:内容以逗号分割):然后通过一系列的文档操作函数处理成为一个二维数组,然后 ...
- 【rocketMQ】1、搭建MQ服务器,生产一个订单与消费一个订单
1. 先解压 2. maven编译安装.(注意虚拟机采用nat网络模式,需要联网) mvn -Prelease-all -DskipTests clean install -U 启动nameser节点 ...
- 再学C/C++ 之 浅析gdb的-g选项
浅析gdb的-g选项 准备 gdb是Linux下学习C/C++最常用的debug工具.要使用这一强大工具,必须在编译时加上-g选项,生成的目标文件才可以用gdb进行调试. 如,先创建一个test. ...
- storm_分组策略
注意1:原始的案例 spout 和bolt都是1个并发 所以文件中30条日志 从spout发出以后 bolt接受到30条
- Android面试题(2)
1. int 和 Integer 有什么区别 Java 提供两种不同的类型:引用类型和原始类型(或内置类型).Int是java的原始数据类型,Integer是java为int提供的封装类.Java为 ...
- Disruptor入门
一.什么是 Disruptor Disruptor是一个高性能的异步处理框架,或者可以认为是最快的消息框架(轻量的JMS),也可以认为是一个观察者模式实现,或者事件-监听模式的实现,直接称disrup ...
- java工具类-日期工具类
1.获得时间戳 为了统一其他语言的如php和unix系统获取的时间戳是10位长度的,精确到秒. java时间戳长度是13位,精确到毫秒 我们获取时间戳需要相应处理. //获取当前时间戳,除以1000, ...
- Tensorflow运用RNN注意事项
一.学习单步的RNN:RNNCell 如果要学习TensorFlow中的RNN,第一站应该就是去了解“RNNCell”,它是TensorFlow中实现RNN的基本单元,每个RNNCell都有一个cal ...