1.数据类型存储
基本数据类型保存在栈内存中
引用数据类型保存在堆内存中,引用数据类型的变量是一个指向堆内存中实际对象的引用,存在栈中
2.浅拷贝
浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝
如果属性是基本数据类型,拷贝的就说基本类型的值,如果属性是引用类型,拷贝的就是内存地址
//封装一个函数进行浅拷贝
function shallowClone(obj) {
//声明一个新的空对象存储拷贝后的数据
const newObj = {}
//遍历对象
for(let key in obj) {
//判断obj中是否有key属性
if(obj.hasOwnProperty(key) ){
//将数据克隆到新对象
newObj[key] = obj[key]
}
}
//返回值这个新对象
return newObj
}
hasOwnProperty(propertyName)
用来检测属性是否为对象自有属性 ,如果是则返回true,否则返回false,参数propertyName为要检测的属性名
hasOwnProperty() 方法是Object的原型方法(也称实例方法),它定义在Object.prototype对象之上,所有的Object的实例对象都可以继承hasOwnProperty()方法
hasOwnPorperty()只会检测对象自有的属性,不会检测对象原型上的属性,但是这些属性又是原型对象本身的自有属性,所以原型对象也可以使用hasOwnProperty()检测自己的自有属性
在JavaScript中,存在浅拷贝的现象有
(1)引用数据类型的直接赋值
(2)Object.assign()
用于将所有可枚举属性的值从一个或多个源对象复制到目标对象.它将返回目标对象
const target = {name:'张三',age:20}
const source = {sex :'男'}
const result = Object.assign(target,source)
console.log(target,target === result)//{name:'张三',age :20, sex:'男'} true
(3)Array.slice(start,end)
可以从已有的数组中返回某个选定的元素,可以提取字符串中的某个部分,并以新的字符串返回被提取的部分
第一个参数 : start ,必须,规定从何处开始选取,如果该参数为负,则表示从原数组的倒数第集合元素开始提取
第二个参数 : end,可选.规定从何处结束提取,该参数是数组片段结束楚数组的下标,不写默认截取从start到数组结束的所有元素,如果为负数,则表示原数组中的倒数第几个元素结束抽取
返回值 : 返回一个新数组,包含从start(包含该元素)到end(不包括该元素)的元素
const obj = [
{
name: '张三',
age: 20,
},
{
name: '李四',
age: 18
}
]
const newObj = obj.slice(0)
obj[1].name = '小花'
console.log(obj, newObj)
slice仅仅拷贝了元素的地址
(4)Array.concat()
连接数组,返回值是连接后的数组
const arr = [
{
name : '熊大',
age : 20,
},
{
name : '熊二',
age : 18,
},
{
name : '光头强',
age : 18,
},
]
const newArr = arr.concat()
newArr[1].name = '吉吉国王'
console.log(arr,newArr)
(5)展开运算符...
const arr = [
{
name : '佩奇',
age : 18
},
{
name : '乔治',
age : 20
},
]
const newArr = [...arr]
newArr[1].name = '小花'
console.log(arr,newArr)
3.深拷贝
深拷贝开辟一个新的栈,两个对象完全相同,但是对应不同的地址,修改一个对象的属性,不会改变另一个对象的属性
常见的深拷贝方式有:
(1)_.cloneDeep()
const _ = require('lodash')
const obj1 = {
a : 1,
b : { f : { g : 1 } },
c : [1,2,3]
}
const obj2 = _.cloneDeep(oobj1)
console.log(obj1.b.f === obj2.b.f)//false
(2).jQuery.extend()
const $ = require('jQuery')
const obj = {
a : 1,
b : { f : { g : 1 } },
c : [ 1, 2, 3]
}
const obj2 = $.extend(true, {}, obj1}
consloe.log(obj1.b.f === obj2.b.f)//false
(3)JSON.stringify()
const obj2 = JSON.parse(JSON.stringify(obj1))
但是这种方式会存在弊端,会忽略undefined symbol 和函数
const obj = {
name : 'a',
name1 : undefined,
name2 : function() {},
name3 : Symbol('a')
}
const obj2 = JSON.parse(JSON.stringify(obj))
console.log(obj2)//{name:'a'}
(4)循环递归
const obj = {
name : '张三',
age : 20,
hobby : ['吃饭','睡觉','打豆豆'],
students :{
name : '小明',
age : 18,
course : 80
}
}
//声明一个函数
function deepClone (obj,obj2){
//遍历这个对象
for(let key in obj){
//如果对象包含数组
if(obj[key] instanceof Array) {
//则创建一个空数组
obj2[key] = []
//递归函数深拷贝数组
deepClone(obj[key],obj2[key])
}else if (obj[key] instanceof Object){//如果对象中包含对象
//则创建一个空对象
obj2[key] = {}
//递归函数深拷贝对象
deepClone(obj[key],obj2[key])
}else {
//如果是值类型就直接拷贝
obj2[key] = obj[key]
}
}
}
//开始拷贝
const obj2 = {}
deepClone(obj,obj2)
console.log(obj,obj2)
4.区别
浅拷贝只拷贝属性指向某个对象的指针,而不是对象本身,修改拷贝后的数据,原数据也会修改
深拷贝则会创造一个一模一样的对象,新对象与原对象不共享内存,修改新对象的数据不会对原数据进行修改