js传递和拷贝详解

我们知道js有几种基本的数据类型和其他的复杂数据类型包括(对象,数组,函数),基本数据类型的赋值其实就是值的拷贝,我们称之为值传递,赋值后的变量和原来的变量除了值相等之外并无其他关联。

let x = 666let y = xlet m = 'abc'let n = my = 888n = 'def'console.log(x, y)//666,888console.log(m, n)//'abc','def'

登录后复制

复杂数据类型的传递并不是这样子的,因为将一个变量绑定到一个复杂数据类型的时候记录的并不是这个复杂数据的值,而是存放了这个数据的一个地址信息,当将这个变量赋值给另一个变量的时候只是将地址传递了过去,这两个变量指向的其实是一个数据信息,当改变任意一个变量的时候,另外的变量都会受到影响,这种传递方式我们称之为引用传递

let obj1 = {    a : '1',    b : 2} let obj2 = obj1obj2.b = 3console.log(obj1,obj2)//{a: "1", b: 3},{a: "1", b: 3}

登录后复制

拷贝

我们知道复杂数据类型的赋值是引用传递,赋值前后的变量会相互影响,在实际项目中我们经常不希望这样子,譬如:

我们在一个view里面有两处用到了data(是一个Array),其一是一个list只要把data按顺序展示即可,其二是一个chart需要把data逆序之后再做数据处理,这时候我们就犯难了,如果直接data.reverse()之后第一处的列表也是逆序的了,这不是我们想见的,我们需要一个方法只复制数组的值,并且这个新数组和原数组的数据地址并不一样,这种复制方式我们称为数组的拷贝。

let obj1 = {a:1, b:{c:2}}let shallowCopy = (src)=> {    let dst = {}    for (let prop in src) {        if (src.hasOwnProperty(prop)) {          dst[prop] = src[prop]        }    }    return dst}let obj2 = shallowCopy(obj1)console.log(obj1,obj2) //@1obj1.a = 6console.log(obj2.a) //@2obj2.b.c = 666console.log(obj1.b.c) //@3obj2.b = {    c: 888}console.log(obj1.b.c) //@4

登录后复制

上面的例子可以看出来obj1的第一层属性是复制属性值,没有继承地址的拷贝,但是第二层就是b属性确实共享一块内存地址的,这就是浅拷贝,但是在@4处obj1却没有收到obj2的影响,是因为属性b是一个对象,这种引用传递的重新赋值,计算机会重新分配一块新的内存来存放数据和记录地址信息,所以这时obj1.b.c和obj2.b.c已经不是记录的一个属性值了

也可以理解为:拷贝是之于传递的,直接对复杂数据类型进行赋值是引用传递,不能称之为拷贝,拷贝是对原数据的单纯的数据备份,数据的内存地址信息并不完全一样,这是因为拷贝还分为浅拷贝和深拷贝。

对复杂数据类型的非嵌套的拷贝,就是只拷贝第一层的数据信息的拷贝是浅拷贝,如果第一层的数据有复杂数据类型,则依然采用引用传递的方式,复制的仍然是地址信息,通过其他方式实现的数组对象等的多层嵌套拷贝就是深拷贝。

下面我们再来看下数组和对象如何来实现深浅拷贝:

数组的拷贝

slice方法

let arr1 = [1,2,[3,4]]let arr2 = arr1.slice(0)arr2[2].push(5)arr2.push(6)console.log(arr1,arr2)

登录后复制

concat方法

let arr1 = [1,2,[3,4]]let arr2 = arr1.concat()arr2[2].push(5)arr2.push(6)console.log(arr1,arr2)

登录后复制

for循环

let arr1 = [1,2,[3,4]]let arr2 = []for(let i = 0; i

登录后复制

…运算符

let arr1 = [1,2,[3,4]]let [...arr2] = arr1arr2[2].push(5)arr2.push(6)console.log(arr1,arr2)

登录后复制

以上4种数组的拷贝都是浅拷贝,要实现数组的深拷贝就要递归实现

let deepClone = (src)=> {    let result    (src instanceof Array) ? (result = []) :(result = {})    for (let key in src) {        result[key] = (typeof src[key] === 'object') ? deepClone(src[key]) : src[key]//数组和对象的type都是object    }    return result}   let arr1 = [1,2,[3,4]]let arr2 = deepClone(arr1)arr2[2].push(5)arr2.push(6)console.log(arr1,arr2)

登录后复制

可以发现用方面的方法arr1[2]和arr2[2]不一样,同样上面的深拷贝的方法也适用于对象

对象的拷贝

万能的for循环

let obj1 = {a:1,b:{c:2}}let obj2 = {}for(let key in obj1){    obj2[key] = obj1[key]}obj1.b.c = 6console.log(obj1,obj2)

登录后复制

…运算符

let obj1 = {a:1,b:{c:2}}let {...obj2} = obj1obj1.b.c = 6console.log(obj1,obj2)

登录后复制

Object.assign()

let obj1 = {a:1,b:{c:2}}let obj2 = Object.assign({},obj1)obj1.b.c = 6console.log(obj1,obj2)

登录后复制

上面3种方法是对象的浅拷贝,再介绍2种对象的深拷贝的方法:

转为字符串再转回对象

let obj1 = {a:1,b:{c:2}}let obj2 = JSON.parse(JSON.stringify(obj1))obj1.b.c = 6console.log(obj1,obj2)

登录后复制

deepClone方法,就是上面的数组的deepClone方法

相关的概念

纯函数

给定函数一个输入返回一个唯一的输出,并且不对外部环境附带任何影响的函数我们称为纯函数,其内定义的变量在函数返回后都会被垃圾回收机制回收掉。

但是如果函数的参数是数组、对象或函数时,传入的是一个引用,对其操作会影响到原来的数据,这样子写的函数会产生附带的影响,使得可读性变低。

降低影响的方式就是对传入参数进行深度拷贝,并赋给一个新的变量,方式原来的参数被篡改。

我们来看一个纯函数的例子:

let pureFunc = (animal)=> {    let newAnimal = JSON.parse(JSON.stringify(animal))    newAnimal.type = 'cat'    newAnimal.name = 'Miao'    return newAnimal}let wang = {    type: 'dog',    name: 'Wang'}let miao = pureFunc(wang)console.log(wang,miao)

登录后复制

通过上面的例子可以看到wang并没有被纯函数所改变值。

大家再来思考一下下面的例子,如果答对了说明你已经对本文所讲的东西有了很深刻的理解了(提醒大家一下—>引用的重新赋值)

let afterChange = (obj)=>{    obj.a = 6    obj = {        a: 8,        b: 9    }    return obj}let objIns = {    a: 1,    b: 2}let objIns2 = afterChange(objIns)console.log(objIns, objIns2)

登录后复制

以上就是我对js的引用和传递的理解,如有不当之处敬请谅解,Thanks!

大家还可以看看一些其他的文章加深理解,我推荐这篇Explaining Value vs. Reference in Javascript。

相关推荐:

js函数的按值传递参数

JavaScript参数传递图解教程

php和js中json传递的简析

以上就是js传递和拷贝详解的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2783278.html

(0)
上一篇 2025年3月8日 16:47:16
下一篇 2025年3月5日 01:39:51

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • js如何获取鼠标当前位置实例

    本文主要和大家分享js如何获取鼠标当前位置实例,希望能帮助到大家。         javascript获得鼠标位置鼠标X轴:鼠标Y轴: function mouseMove(ev) { Ev = ev || window.event; v…

    编程技术 2025年3月8日
    200
  • js兼容性问题详解

    本文主要和大家分享js兼容性问题详解, 1.HTML对象获取问题 FireFox:document.getElementById(“idName”); ie:document.idname或者document.getElementById(…

    编程技术 2025年3月8日
    200
  • JS实现粘贴到剪贴板实例代码分享

    本文主要和大家分享JS实现粘贴到剪贴板实例代码,目前常见的实现粘贴到剪贴板主要有以下两种方法,希望能帮助到大家。 第三方库 clipboard 原生js, 主要是 document.execcommand方法 第一种方法按照文档说明,设置触…

    编程技术 2025年3月8日
    200
  • js混入式继承实例详解

    1.运用场景:假设有两个对象o1,o2,如果要把o2的方法和属性拷贝到o1中,混入式继承是最简便的方法之一 2.实现方式:用for…in…的方式遍历o2对象的属性和方法,并将o2的属性和方法赋值给o1 代码实现 function mixEx…

    编程技术 2025年3月8日
    200
  • rxjs的详解

    这次给大家带来rxjs的详解,使用rxjs的注意事项有哪些,下面就是实战案例,一起来看一下。 rxjs(Reactive Extensions for JavaScript)是Javascript的响应式扩展, 响应式的思路是把随时间不断变…

    编程技术 2025年3月8日
    200
  • js进行浏览器的Cookies设置实例

    Cookies现在经常被大家提到,那么到底什么是Cookies,它有什么作用呢?Cookies是数据包,可以让网页具有记忆功能,在某台电脑上记忆一定的信息。Cookies的工作原理是,第一次由服务器端写入到客户端的系统中。以后每次访问这个网…

    编程技术 2025年3月8日
    200
  • 用JS代码做出弹幕效果

    这次给大家带来用js代码做出弹幕效果,用js代码做出弹幕效果的注意事项有哪些,下面就是实战案例,一起来看一下。 实现原理 1、设置展示弹幕元素位置属性为relative2、动态创建弹幕元素,位置属性设置absolute,left为展示宽度3…

    编程技术 2025年3月8日
    200
  • js中数组函数和注意事项

    本文主要和大家分享js中数组函数和注意事项,首先我们先和大家分享js 的数组对象有哪些,希望能帮助到大家。 js 的数组对象有哪些 push       — 向数组的末尾添加一个或更多元素,并返回新的长度。 pop        — 删除并…

    编程技术 2025年3月8日
    200
  • js中const,var,let区别分享

    本文主要和大家分享js中const,var,let区别,希望能帮助到大家。 const 不可以修改 并且必须初始化 const NAME;Uncaught SyntaxError: Missing initializer in const …

    编程技术 2025年3月8日
    200
  • js中的sort()使用方法

    如果调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码的顺序进行排序。要实现这一点,首先应把数组的元素都转换成字符串(如有必要),以便进行比较。 array.sort()方法默认是升序排序,如果想按照…

    编程技术 2025年3月8日
    200

发表回复

登录后才能评论