JS的数据分类
JS的数据分为两大类型:
一、 基本数据类型 或者说原始数据类型(以下统称基本数据类型)
Undefined – 变量声明但未赋值,或者函数没有返回值
Null – 空
Boolean – 布尔值 true false
Number – 数值型
(JS是弱类型语言,并没有具体到整型浮点型这些 所有的数值 都是Number 包括NaN(数值非法运算的结果))
String – 串
Symbol – ES6新增的 基本数据类型 “symbol类型通常被用作一个对象属性的键值——当你想让它是私有的时候”
这里不详细介绍symbol 类型
简单了解symbol --> 推荐链接
深入了解symbol --> symbol官方介绍
注:值得一提的是 null 的typeof 返回值是object 这也是JS 历史遗留的之一(刚开始设计JS的时候,所有以0开头表示的数据均为Object,似乎是这样的,不太确定,感兴趣可以自行百度)
二、引用数据类型
- Object 对象:数据的无序集合
- Array 数组: 数据的有序集合
- Function 函数
(Object 是所有引用类型数据 在原型链中的根 这也是“万物皆对象”说法的来源)
基本数据类型和引用数据类型的区别
说到这里就不得不说一下计算机中**栈(stack)和堆(heap)**两种数据结构的定义
stack是计算机自动分配的空间,它由系统自动释放。而heap则是动态分配的内存。
借鉴:JS基本数据类型和引用数据类型的区别及深浅拷贝
这里总结一下:
简单来说,基本类型是指被存在于栈中的简单数据段,它们是直接按值存放的,所以可以直接按值访问
所以两个基本类型copy后,在重新被赋值时,是不会受影响的,因为b拿到的是a的值,也叫传值:
var a = 10;
var b = a;
b = 20;
console.log(a); // 10值
console.log(b); // 20值
但是引用类型却不一样,引用类型是被存放在堆内存的对象,而变量保存的只是栈内存中的指针,这个指针指向堆内存中该对象真正的值,使用这个变量时,计算机通过变量中保存的地址快速找到堆内存中该变量的值。
那么这就造成了引用类型数据在直接copy时的现象(浅拷贝):
var obj1 = new Object();
var obj2 = obj1;
obj2.name = "我有名字了";
console.log(obj1.name); // 我有名字了
obj1 “赋值” 给obj2 后,我们改变obj2的属性和属性值,obj1也跟着改变了,原因就是赋值的时候obj2拿到的只是obj1中保存的指向对象的值的地址,也叫传址,对于引用类型的数据来说,传址就会造成“浅拷贝”。
如何实现深copy?
实现深copy(也就是像基本类型数据那样,达到复制后不会相互影响的目的),首先我们可以遍历传值:
let people1 = {
name: "林志颖",
age: 46,
};
let people2 = {};
for (let i in people1) {
people2[i] = people1[i];
}
console.log(people2); // {name: "林志颖", age: 46,}
people2.name = "郭德纲";
console.log(people2); // {name: "郭德纲", age: 46,}
console.log(people1); // {name: "林志颖", age: 46,}
但是,这种只能实现一层的深拷贝,也就是当引用类型数据的元素或者属性值依旧是个引用类型数据时,比如[1, 2, ["a", "b"]]
,这样我们就需要封装一下,利用递归来实现:
function deepCopy(obj, newObj) {
var newObj = newObj || {};
for (var i in obj) {
if (typeof obj[i] === "object") {
newObj[i] = obj[i].constructor === Array ? [] : {};
deepCopy(obj[i], newObj[i]);
} else {
newObj[i] = obj[i];
}
}
return newObj;
}
let people1 = {
name: "林志颖",
age: 46,
grade: {
sing: 99,
xiangsheng: 60,
},
};
let people2 = {};
deepCopy(people1, people2);
people2.name = "郭德纲";
people2.grade.xiangsheng = 99;
console.log(people1);
console.log(people2);
结果:
当然,深copy 还有更加粗暴的方式··· 那就是利用JSON的转换:
function deepCopy_JSON(obj) {
let newObj = obj.constructor === Array ? [] : {};
newObj = JSON.parse(JSON.stringify(obj));
return newObj;
}
let arr1 = [1, 2, ["a", "b", "c"], { name: "林志颖" }];
let arr2 = deepCopy_JSON(arr1);
arr2[2][2] = "d";
arr2[3].name = "郭德纲";
console.log(arr1);
console.log(arr2);
结果:
补充:关于obj.assign() 是深拷贝还是浅拷贝:(视情况而定)
首先:obj.assign 方法 拷贝的是属性值;
也就是说,对于Object.assign()而言, 如果对象的属性值为简单类型(string, number),通过Object.assign({},srcObj);得到的新对象为‘深拷贝’;如果属性值为对象或其它引用类型,那对于这个对象而言其实是浅拷贝的。这是Object.assign()特别值得注意的地方。
补充来源:JS-object.assign