一、理解基础数据类型和引用数据类型
-
基础数据类型:
- 字符串(String):表示文本数据,使用引号括起来。
- 数字(Number):表示数值数据,包括整数和浮点数。
- 布尔值(Boolean):表示逻辑值,即 true 或 false。
- 空值(Null):表示一个空值或不存在的值。
- 未定义(Undefined):表示一个未定义的值。
- 符号(Symbol)(ES6新增):表示唯一的、不可改变的值。
-
引用数据类型:
- 对象(Object):表示复杂数据结构,可以包含多个键值对。
- 数组(Array):一种特殊的对象,用于存储多个值。
- 函数(Function):也是对象的一种,用于封装可执行的代码块。
- 日期(Date):表示日期和时间。
- 正则表达式(RegExp):用于匹配字符串的模式。
- 其他引用数据类型:如 Map、Set 等(ES6新增)。
基础数据类型存储在栈内存中,并且它们的值直接按值访问,因此可以直接操作实际的值(基础数据类型进行赋值操作时,会创建一个新的值,而不是共享同一块内存地址。)。而引用数据类型的值存储在堆内存中,栈内存中存储的是指向堆内存中实际数据的引用,因此对引用数据类型的操作实际上是对内存地址的操作,多个变量或对象可以共享同一个引用,导致共享内存地址。
二、赋值、浅拷贝、深拷贝的概念。
赋值:赋值是指将一个变量的值或引用复制给另一个变量。在赋值操作中,如果原始数据是引用类型(如对象、数组),则赋值操作后两个变量将指向同一块内存地址,修改其中一个变量的值也会影响另一个变量。
浅拷贝:浅拷贝是指创建一个新的对象或数组,然后将原始对象或数组中的元素复制到新对象或数组中。浅拷贝只复制对象或数组的第一层结构,如果对象或数组中包含引用类型的元素(如嵌套对象、数组),则这些引用类型的元素仍然是共享的,即新旧对象中的引用类型元素指向同一块内存地址。
深拷贝:深拷贝是指创建一个全新的对象或数组,并且递归地复制原始对象或数组中的所有嵌套对象或数组,确保新对象与原始对象完全独立,互不影响。深拷贝会复制整个对象的结构,包括所有嵌套的对象和数组,每个元素都是独立的,不存在共享引用。
总结: 赋值是简单的值或引用传递,在引用类型中会共享内存地址;浅拷贝会复制第一层结构,但嵌套结构还是共享内存地址;而深拷贝则会复制所有层级的结构,确保完全独立。在编程中,根据需求选择适当的复制方式非常重要,以避免意外的数据改动和副作用。
三、赋值、浅拷贝、深拷贝的应用场景、实现方式
1、赋值
应用场景:
处理基本数据类型时,直接赋值是最简单的方式。
处理引用数据类型的时候需要考虑是否要修改原数据、修改的话可以用赋值。
实现演示
代码
<template><div class="home"><h3>这是vue2测试页面</h3><p>num值:{{ num }}</p><p>obj:{{ obj }}</p><p><button @click="change">修改信息</button></p></div>
</template><script>export default {data() {return {num: '1',obj: { name: 'zs', age: 20 }}},created() {},methods: {change() {let newNum = this.num;newNum = 2;let newObj = this.objnewObj.age = '18'console.log('num的值为: '+ this.num + ' newNum的值为: ' + newNum);console.log('obj的值为: '+ this.obj + ' newObj的值为: ' + newObj);}},
}
</script>
<style>.home{margin: 0 auto;text-align: center;}
</style>
未点击修改按钮前
点击修改按钮后
结论
通过赋值、基础数据类型的数据赋值给一个新数据、新数据改变不影响旧数据(不共享内存空间)
通过赋值、引用数据类型的数据赋值给一个新数据、新数据改变影响旧数据(共享内存空间)
2、浅拷贝
应用场景:
处理引用数据类型的时、希望修改新数据(新数据没有嵌套引用类型)时不影响原数据。
实现演示
代码
实现浅拷贝的几种不同方式代码
// 方式一、使用ES6的展开运算符(...) 适用于对象和数组
// 浅拷贝对象
const originalObject = { name: 'Alice', age: 30 };
const shallowCopyObject = { ...originalObject };// 浅拷贝数组
const originalArray = [1, 2, 3];
const shallowCopyArray = [...originalArray];console.log(shallowCopyObject); // 输出: { name: 'Alice', age: 30 }
console.log(shallowCopyArray); // 输出: [1, 2, 3]// 方式二、使用Object.assign()方法 适用于对象
const originalObject = { name: 'Bob', age: 25 };
const shallowCopyObject = Object.assign({}, originalObject);console.log(shallowCopyObject); // 输出: { name: 'Bob', age: 25 }// 方式三、使用Array.slice()方法 适用于数组
const originalArray = [7, 8, 9];
const shallowCopyArray = originalArray.concat();console.log(shallowCopyArray); // 输出: [7, 8, 9]// 方式四、使用Array.concat()方法 适用于数组
const originalArray = [7, 8, 9];
const shallowCopyArray = originalArray.concat();console.log(shallowCopyArray); // 输出: [7, 8, 9]
实现浅拷贝效果代码
<template><div class="home"><h3>这是vue2测试页面</h3><p>num值:{{ num }}</p><p>obj:{{ obj }}</p><p><button @click="change">修改信息</button></p></div>
</template><script>export default {data() {return {num: '1',obj: { name: 'zs', age: 20, family: { son:'ls', daughter:'ww' }},arr: [1,2,3,4],}},created() {},methods: {change() {let newNum = this.num;newNum = 2;let newObj = {...this.obj}newObj.age = 18newObj.family.son = 'zl'console.log('num的值为: '+ this.num + ' newNum的值为: ' + newNum);console.log(this.obj, newObj);}},
}
</script>
<style>.home{margin: 0 auto;text-align: center;}
</style>
未点击修改按钮前
点击修改按钮后
结论
引用数据类型的数据浅拷贝给一个新数据
新数据基础数据类型数据的改变不影响旧数据(不共享内存空间)
新数据引用数据类型的改变影响旧数据(不共享内存空间)
3、深拷贝
应用场景:
处理引用数据类型的时、希望修改新数据(新数据包含嵌套引用类型)时不影响原数据。
使用深拷贝时,需要考虑性能开销、循环引用、数据类型的处理、不可枚举属性的保留以及对象方法的处理等问题
实现演示
代码
实现深拷贝的几种不同方式代码
// 方式一 使用 JSON.stringify() 和 JSON.parse() 适用于对象和数组的深拷贝。但请注意,它无法拷贝一些特殊类型,如函数、正则表达式等
const originalObject = { name: 'Alice', age: 30 };
const deepCopyObject = JSON.parse(JSON.stringify(originalObject));console.log(deepCopyObject); // 输出: { name: 'Alice', age: 30 }// 方式二、使用递归
function deepCopy(obj) {if (typeof obj !== 'object' || obj === null) {return obj;}let copy;if (Array.isArray(obj)) {copy = [];for (let i = 0; i < obj.length; i++) {copy[i] = deepCopy(obj[i]);}} else {copy = {};for (let key in obj) {if (obj.hasOwnProperty(key)) {copy[key] = deepCopy(obj[key]);}}}return copy;
}const originalObject = { name: 'Bob', age: 25 };
const deepCopyObject = deepCopy(originalObject);console.log(deepCopyObject); // 输出: { name: 'Bob', age: 25 }// 使用第三方库:如 Lodash 的 cloneDeep() 方法和 jQuery 的 extend() 方法
// 使用 Lodash 的 cloneDeep() 方法
const originalObject = { name: 'Alice', age: 30 };
const deepCopyObject = _.cloneDeep(originalObject);console.log(deepCopyObject); // 输出: { name: 'Alice', age: 30 }// 使用 jQuery 的 extend() 方法
const originalObject = { name: 'Bob', age: 25 };
const deepCopyObject = $.extend(true, {}, originalObject);console.log(deepCopyObject); // 输出: { name: 'Bob', age: 25 }
实现深拷贝效果代码
<template><div class="home"><h3>这是vue2测试页面</h3><p>num值:{{ num }}</p><p>obj:{{ obj }}</p><p><button @click="change">修改信息</button></p></div>
</template><script>export default {data() {return {num: '1',obj: { name: 'zs', age: 20, family: { son:'ls', daughter:'ww' }},arr: [1,2,3,4],}},created() {},methods: {change() {let newNum = this.num;newNum = 2;let newObj = JSON.parse(JSON.stringify(this.obj))newObj.age = 18newObj.family.son = 'zl'console.log('num的值为: '+ this.num + ' newNum的值为: ' + newNum);console.log(this.obj, newObj);}},
}
</script>
<style>.home{margin: 0 auto;text-align: center;}
</style>
未点击修改按钮前
点击修改按钮后
结论
引用数据类型的数据深拷贝给一个新数据
新数据改变不影响旧数据(不共享内存空间)
四、总结
1、赋值
处理基本数据类型时,直接赋值是最简单的方式(会生成一个新的内存空间、不会共享内存空间,即不会修改原数据)。
处理引用数据类型的时候需要考虑新数据修改是否能影响原数据、能影响的话可以用赋值(不会生成一个新的内存空间、会共享内存空间,会修改原数据)。
2、浅拷贝
处理引用数据类型的时、希望修改新数据时不能影响原数据(基础数据类型修改后原数据不会修改、引用数据类型修改后原数据会修改)。
3、深拷贝(慎用)
处理引用数据类型的时、希望修改新数据时不能影响原数据(基础数据类型修改后和引用数据类型修改后原数据都不会修改)。