小感在前

React学习与开发过程要经历一个相当长的准备阶段,此前看阮一峰老师的文章中,他就特别提到这一点。但是,由于React框架或者说是一种优秀的前端架构实在太诱人,所以,掌握这项技术所涉及的技术栈过程中经历的任何苦恼都是值得的。在还没有全面掌握这项技术的不断探索过程中,如果包括后端的一部分在内(例如Node.js和Express等,还有一些数据库及API知识),至少要有几十部分,仅限于核心的算起来也有十多项吧。
作为一个基础部分,ES6势在必学。此前,我曾得意于自己已经掌握了一定程度的JS知识,但是在匆读阮老师的《ES6标准入门》一书后才感觉自己落后许多了。同时,在阅读本书的过程中,也发现:这本书或者整个ES6,的确是为着眼于将来的“一统前后端”的大项目作准备的,因此,重复地专门学习这个语言是没有必要的。这是一本案头书,需要什么时再读什么更合适。
本文罗列的就是在本人在学习Redux过程中在遭遇到JS的深浅拷贝过程中总结的相关内容。太匆忙与粗略,仅供同学们参考。

JavaScript 中变量的赋值

结论:JavaScript中变量的赋值分为「传值」与「传址」。

基本数据类型的赋值,就是「传值」;而引用类型变量赋值,实际上是「传址」。
基本数据类型变量的赋值、比较,只是值的赋值和比较,也即栈内存中的数据的拷贝和比较,参见如下代码:

var num1 = 123;
var num2 = 123;
var num3 = num1;
num1 === num2; // true
num1 === num3; // true
num1 = 456;
num1 === num2; // false
num1 === num3; // false

引用数据类型变量的赋值、比较,只是存于栈内存中的堆内存地址的拷贝、比较,参加如下代码:

var arr1 = [1, 2, 3];
var arr2 = [1, 2, 3];
var arr3 = arr1;
arr1 === arr2; // false
arr1 === arr3; // true
arr1 = [1, 2, 3];
arr1 === arr2; // false
arr1 === arr3; // false

JavaScript 中变量的拷贝

JavaScript中的拷贝区分为「浅拷贝」与「深拷贝」。

浅拷贝

浅拷贝只会将对象的各个属性进行依次复制,并不会进行递归复制,也就是说只会进行赋值目标对象的第一层属性。

对于目标对象第一层为基本数据类型的数据,就是直接赋值,即「传值」;而对于目标对象第一层为引用数据类型的数据,就是直接赋存于栈内存中的堆内存地址,即「传址」。

深拷贝

深拷贝不同于浅拷贝,它不但拷贝目标对象的第一层属性,而且还递归拷贝目标对象的所有属性。

一般来说,在JavaScript中考虑复合类型的深层复制的时候,往往就是指对于 Date 、Object 与 Array 这三个复合类型的处理。我们能想到的最常用的方法就是先创建一个空的新对象,然后递归遍历旧对象,直到发现基础类型的子节点才赋予到新对象对应的位置。

不过这种方法会存在一个问题,就是 JavaScript 中存在着神奇的原型机制,并且这个原型会在遍历的时候出现,然后需要考虑原型应不应该被赋予给新对象。那么在遍历的过程中,我们可以考虑使用 hasOwnProperty 方法来判断是否过滤掉那些继承自原型链上的属性。

Object.assign

Object.assign 方法可以把 任意多个的源对象所拥有的自身可枚举属性 拷贝给目标对象,然后返回目标对象。
注意:

对于访问器属性,该方法会执行那个访问器属性的 getter 函数,然后把得到的值拷贝给目标对象,如果你想拷贝访问器属性本身,请使用 Object.getOwnPropertyDescriptor() 和 Object.defineProperties() 方法;
字符串类型和 symbol 类型的属性都会被拷贝;
在属性拷贝过程中可能会产生异常,比如目标对象的某个只读属性和源对象的某个属性同名,这时该方法会抛出一个 TypeError 异常,拷贝过程中断,已经拷贝成功的属性不会受到影响,还未拷贝的属性将不会再被拷贝;
该方法会跳过那些值为 null 或 undefined 的源对象;

利用 JSON 进行忽略原型链的深拷贝

var dest = JSON.parse(JSON.stringify(target));

同样的它也有缺点:
该方法会忽略掉值为 undefined 的属性以及函数表达式,但不会忽略值为 null 的属性。

借助于Lodash 的 merge 方法

在Redux开发中的一个应用是借助于Lodash 的 merge 方法可以实现深拷贝,达到管理范式化数据的目的,示例代码如下:

import merge from "lodash/object/merge";function commentsById(state = {}, action) {switch(action.type) {default : {if(action.entities && action.entities.comments) {return merge({}, state, action.entities.comments.byId);}return state;}}
}

存在大量深拷贝需求时借助immutable库

实际上,即使我们知道了如何在各种情况下进行深拷贝,我们也仍然面临一些问题: 深拷贝实际上是很消耗性能的。(我们可能只是希望改变新数组里的其中一个元素的时候不影响原数组,但却被迫要把整个原数组都拷贝一遍,这不是一种浪费吗?)所以,当你的项目里有大量深拷贝需求的时候,性能就可能形成了一个制约的瓶颈了。

immutable的作用是通过immutable引入的一套API,实现:

1.在改变新的数组(对象)的时候,不改变原数组(对象)
2.在大量深拷贝操作中显著地减少性能消耗

参考代码:
const { Map } = require('immutable')
const map1 = Map({ a: 1, b: 2, c: 3 })
const map2 = map1.set('b', 50)
map1.get('b') // 2
map2.get('b') // 50

尽量保持数据设计的扁平化与科学设计Reducer

在React+Redux开发中,经常要遇到不可变数据的更新问题。复杂情形中,往往需要复制嵌套数据的所有层级。但不幸的是,正确地使用不变的更新去深度嵌套状态的过程很容易变得冗长难读。 更新 ate.first.second[someId].fourth 的示例(http://www.redux.org.cn/docs/recipes/reducers/ImmutableUpdatePatterns.html)大概如下所示:

function updateVeryNestedField(state, action) {return {....state,first : {...state.first,second : {...state.first.second,[action.someId] : {...state.first.second[action.someId],fourth : action.someValue}}}}
}

显然,每一层嵌套使得阅读更加困难,并给了更多犯错的机会。这是其中一个原因,鼓励你保持状态扁平,尽可能构建小巧而灵活的Reducer。

引用

1,https://juejin.im/post/5acc7e606fb9a028c67609f7
2,https://zhuanlan.zhihu.com/p/28508795
3,http://www.zsoltnagy.eu/cloning-objects-in-javascript/
4,http://www.cnblogs.com/penghuwan/p/7359026.html
5,https://blog.csdn.net/github_38524608/article/details/78812761
6,https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_syntax
7,http://www.redux.org.cn/docs/recipes/reducers/UpdatingNormalizedData.html

ES6深拷贝与浅拷贝相关推荐

  1. ES5、ES6深拷贝、浅拷贝

    看这个文章之前,看一下这个作者的文档,讲了一下堆和栈.基本数据和引用数据,比较基础的一些东西:https://www.cnblogs.com/echolun/p/7889848.html 如何区分深拷 ...

  2. ES6之object.assign()是深拷贝还是浅拷贝

    ES6之object.assign()是深拷贝还是浅拷贝 1.概念 浅拷贝--只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存. 深拷贝--会另外创造一个一模一样的对象,新对象跟 ...

  3. JavaScript ES6中的深拷贝和浅拷贝

    今天在做Vue项目时,遇到了涉及到对象展开运算符"..."是深拷贝还是浅拷贝的问题,在问答里看到了这篇回答,由于无法转载,在这里记录一下. 先来了解下,浅拷贝和深拷贝各自的含义: ...

  4. 深拷贝和浅拷贝(Es6)

    目录 深拷贝和浅拷贝 深拷贝和浅拷贝,都只针对应用类型的数据. 一.浅拷贝 1. 扩展运算符 2.Object.assign( ) 二.深拷贝 1.JSON对象的方法 2.手写函数实现深拷贝 深拷贝和 ...

  5. JS的深拷贝和浅拷贝

    今天,CVTE面试官问了深拷贝和浅拷贝的问题 我的回答是:浅拷贝是拷贝了对象的引用,当原对象发生变化的时候,拷贝对象也跟着变化:深拷贝是另外申请了一块内存,内容和原对象一样,更改原对象,拷贝对象不会发 ...

  6. 低门槛彻底理解JavaScript中的深拷贝和浅拷贝

    在说深拷贝与浅拷贝前,我们先看两个简单的案例: //案例1 var num1 = 1, num2 = num1; console.log(num1) //1 console.log(num2) //1 ...

  7. 栈在前端中的应用,顺便再了解下深拷贝和浅拷贝!

    详解栈在前端中的应用 一.栈是什么 二.栈的应用场景 三.前端与栈:深拷贝与浅拷贝 1.JS数据类型 (1)js数据类型的分类 (2)js数据类型的定义和存储方式 (3)js数据类型的判断方式 2.深 ...

  8. ES6 深拷贝_你别自以为是:ES6误区 之 Object.assign()、const

    文/北妈 阅读本文需要 2.3分钟 一 很久没发技术文,今天北妈在新开一个技术系列:"别自以为是,1分钟走出JS常见误区",里面我会每期挑选几个常见基础属性,讲一讲里面最容易被人忽 ...

  9. vb.net中递归退到最外层_面试题被问到再也不慌,深究JavaScript中的深拷贝与浅拷贝...

    " 点个关注,养成习惯,带你python爬虫的过程中学习前端 " JavaScript中的深拷贝和浅拷贝是前端面试中频繁被问到的一道题, 于是我也自己去查阅了一些资料, 然后动手敲 ...

最新文章

  1. 动森服务器维护时长,《动森》在两三年内都会不断更新内容 保证游戏体验
  2. 文法G[E]分析表分析字符串(i+)-编译原理
  3. C++语言基础 —— STL —— 容器与迭代器 —— heap
  4. php 常用函数 180,php 部分常用函数
  5. invoke 魔术_PHP常用魔术方法(__invoke魔术方法)
  6. 我的gentoo安装纪念贴移植空间版
  7. 检查Mysql引擎的方法
  8. 使用JS完成一个简单的计算器功能
  9. rapidminer decision tree(决策树)手册
  10. 鹰式价差matlab,鹰式期权:什么叫铁鹰式期权组合,蝶式价差期权?
  11. 输入年份和月份输出该月有多少天python_输入年份和月份,输出该月有多少天,判断这一天是该年的第几天...
  12. Python爬虫第四课 appium和第MongoDB数据库
  13. 产品管理(Product Management)
  14. 作为菜鸟的我,努力学编程就对了——初来乍到篇
  15. 【花开朝颜复夕颜】—记火影中挚爱的女忍者
  16. SAP FI/CO 顾问面试问题1(转帖)
  17. Autosar学习笔记——(三)诊断服务
  18. HTML5字母为30px用h几,HTML 中 1pt 等于多少 px?
  19. 我们不做看客,只做时代的赋能者—FMI2018人工智能与大数据高峰论坛圆满落幕...
  20. 天正lisp修改了配置_天正建筑常见问题及解决方法.doc

热门文章

  1. php执行URL解析
  2. Linux CPU数量判断命令
  3. ASP.NET中用healthMonitor属性用
  4. ASP.NET管理状态的十种途径
  5. Linux socket 网络编程 常用头文件
  6. 在图像变换中用最小二乘法求解仿射变换参数
  7. matlab图像处理命令(二)
  8. Qt中文手册 之 QTreeWidgetItem
  9. 报文如何截取时间_5种报文、8种邻居状态机详解OSPF工作原理
  10. eclipse插件 android模拟器,关于eclipse:ADT插件中的android模拟器没有运行