一、数据类型
- 值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。
- 引用数据类型:对象(Object)、数组(Array)、函数(Function)。
二、存储方式及复制、拷贝
首先内存中分为两块区域一块叫栈,一块叫堆。
- 基础数据类型保存在栈内存中。例如
var a = 1
var b = a
这里’1’是数值类型,这时会在栈上开辟一个空间 用来去存储它,那a就是用来调用他的名字。b = a,这时,又会在栈上开辟一个空间,这里面存着跟a一样的值’1’,但它的名字为b,所以到这时内存中现在有两个空间,分别存储着数值’1’,一个是空间为a,一个是空间为b,如果这时b = 2,会在先找到b的空间,把1替换成2,那其实对a是没有任何影响的,
栈 | 堆 |
---|---|
a=1 | |
b=1 |
但是当数据类型为字符串数据类型时就又有变化了,例如
var str = 'abc'
var str2 = str
这段代码和数值类型一样,先在栈上开辟空间,存对应的字符串。
栈 | 堆 |
---|---|
str = ‘abc’ | |
str2 = ‘abc’ |
但是当改变str2的值的时候str2 = 'abcd'
,不会到str2的空间直接把’abc’替换为’abcd’,而是开辟新的空间去存储新的值,然后把变量名指向新的空间,旧的空间由于没有名字调用了会被删除回收。这也是字符串的不可改变性。
undefined 和 null 就是在栈上开辟空间存上undefined 和 null
- 引用数据类型的指针(对象的地址)保存在栈内存中,数据保存在堆内存中。
var obj = {
name:'zs'
age: 18
}
栈 | 堆 |
---|---|
obj_address(对象地址) | name:‘zs’ ,age: 18 |
对象的复制,以及浅拷贝的区别,简单的复制只是引用的拷贝。浅拷贝是拷贝一层,更深层次对象级别的也只拷贝引用。浅拷贝可以通过Object.assign(target, ...sources)
或对象遍历实现。
var obj1 = {
name: 'zs'
}
var obj2 = obj1
//这时只是将obj1的的地址赋值给obj2,地址还是指向同一个对象,所以
//当后面执行obj2.name = '123'的时候,obj1.name也为123
var obj3 = {}
for (k in obj1) {
obj3[k] = obj1[k]
}
//浅拷贝的一种方式,当前拷贝了一层所以obj3.name的值为zs而不是123
console.log(obj1.name, obj2.name, obj3.name);//zs zs zs
obj2.name = '123'
console.log(obj1.name, obj2.name, obj3.name);//123 123 zs
而深拷贝则是拷贝多层,对每一级别的数据都会进行拷贝。可以理解为在堆内存中开辟了新的空间,将要拷贝的对象完完全全的复制了一份新的数据放入其中,然后在栈内存中有一个新的引用指向它。此时,修改它的内容将不会影响拷贝的父本。深拷贝可以通过json
转换的方式实现,例如
var obj1 = { body: { a: 10 } };
var obj2 = JSON.parse(JSON.stringify(obj1));
或者递归
function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
var prop = initalObj[i]; // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
if(prop === obj) {
continue;
}
if (typeof prop === 'object') {
obj[i] = (prop.constructor === Array) ? [] : {};
arguments.callee(prop, obj[i]);
} else {
obj[i] = prop;
}
}
return obj;
}
var str = {};
var obj = { a: {a: "hello", b: 21} };
deepClone(obj, str);
console.log(str.a);
以及lodash函数库实现深拷贝。