赋值与拷贝

6 篇文章 0 订阅
3 篇文章 0 订阅

##深入赋值、拷贝问题

要说赋值的问题的话就必须先说基本数据类型和引用数据类型;

1.基本数据类型和引用数据类型

@1 基本数据类型指的是简单的数据段;

@2 引用数据类型指的是那些可能由多个值构成的对象

  • @1@2出自于JavaScript高级程序设计第三版

@3 截止今年(2019)的ES10,js的基本数据类型已经来到了七种;

string(字符串)、number(数字)、boolean(布尔)、null(对空)、undefined(未定义)、Symbol(独一无二的值-ES6)、BigInt(任意大的整数-ES10)

@4 常用的引用类型有

Object(对象)、Array(数组)、Date(日期)、RegExp(实例)、Function(函数);还有许多,这些只是常用的。

!!!string在ECMAScript中不属于对象形式不是引用类型。

2.赋值

@1 在将一个值赋给变量时,解析器必须确定这个值是基本类型还是引用类型

@2 赋值分为两部分

基本数据类型:赋值,赋值之后两个变量互不影响
引用数据类型:赋址,两个变量具有相同的引用,指向同一个对象,相互之间有影响

let num1 = 5let num2 = num1
--
num25(number类型)
num15(number类型)
let obj1 = new Object()
let obj2 = obj1
obj1.name = 'tom'
console.log(obj2.name) // 'tom'
--
obj2(Object类型)
obj1(Object类型)

!!!为了解决此问题影响,就要使用浅拷贝或深拷贝。

3.浅拷贝

浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是引用类型,拷贝的就是它的内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。即默认拷贝构造函数只是对对象进行浅拷贝复制(逐个成员依次拷贝),即只复制对象空间而不复制资源。

实现浅拷贝

@1 Object.assign()

用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

const obj = { a: 1,test:{sys:2} };
const copy = Object.assign({}, obj);
obj.test.sys = 3
console.log(copy); // { a: 1, test: Object { sys: 3 } }

@2 展开语法(Spread syntax) - MDN

可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开;还可以在构造字面量对象时, 将对象表达式按key-value的方式展开。

  • 函数调用
    myFunction(...iterableObj);
  • 字面量数组构造或字符串:
    [...iterableObj, '4', ...'hello', 6];
  • 构造字面量对象时,进行克隆或者属性拷贝ES9(ECMAScript 2018)规范新增特性:
    let objClone = { ...obj };

eg:

const values = this.state.value
values.push(this.state.detailed)

上面利用赋值然后直接修改新变量会影响this.state.value因此造成页面渲染的bug

const values = [...this.state.value]
values.push(this.state.detailed)

利用数组扩展运算符则可避免此情况

@3 部分数组方法

Array.prototype.copyWithin() // 方法浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度

Array.prototype.slice()     //  返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝

Array.prototype.concat()     //  用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。

Array.from()   // 从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例

4.深拷贝

一个引用对象一般来说由两个部分组成:一个具名的Handle,也就是我们所说的声明(如变量)和一个内部(不具名)的对象,也就是具名Handle的内部对象。它在Manged Heap(托管堆)中分配,一般由新增引用对象的New方法是进行创建。深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。

实现深拷贝

@1 JSON方法

JSON.parse(JSON.stringify(object))
该方法有缺陷:会忽略 undefined、symbol、函数、正则

let obj = {
    name: 'tom',
    a: undefined,
    b: Symbol('tom'),
    c: function() {},
	d: /'123'/
}
let b = JSON.parse(JSON.stringify(obj));
console.log(b);
// {name: "tom"}

@2 递归函数

let deepClone = function (obj) {
    let copy = Object.create(Object.getPrototypeOf(obj));
    let propNames = Object.getOwnPropertyNames(obj);
    propNames.forEach(function (items) {
        let item = Object.getOwnPropertyDescriptor(obj, items);
        Object.defineProperty(copy, items, item);
    });
    return copy;
};
let obj ={name:'tom'}
console.log(deepClone(obj))
// {name: "tom"}

###@3 其他
jQuery.extend()、lodash.cloneDeep() 也可以实现深拷贝

5.总结

-
堆内存指向基本数据类型引用数据类型
赋值(引用类型)改变会使基本数据类型一同改变改变会使引用数据类型一同改变
浅拷贝是(引用类型)改变不会使基本数据类型一同改变改变会使引用数据类型一同改变
深拷贝改变不会使基本数据类型一同改变改变不会使引用数据类型一同改变

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值