JS数据类型 | 青训营笔记

40 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 16 天

知识点

  • JavaScript 变量、作用域、闭包、this、原型及原型链
  • JavaScript 事件循环
  • ES6+ 新特性

JavaScript 数据类型

面试中经常被问到 JavaScript 数据类型都有哪些?有些时候面试者因为紧张连这最基础的题目都回答不出来或者回答不够全面,下面我们来具体了解下 JavaScript 数据类型吧!

首先,需要答出 JavaScript 数据类型分为基本类型(简单类型)和引用类型(复杂类型)两种,分别是:

基本类型

  • string (字符串)
  • boolean (布尔)
  • number (数字)
  • undefined (undefined)
  • null (null)
  • symbol (代表创建后独一无二且不可变的数据类型)

引用类型

  • Object (对象)
  • Array (数组)
  • Function (函数)

这个时候面试官可能又会接着问:那你知道这两种数据类型有什么区别吗?

  • 存放位置不同

基本类型的变量会保存在栈内存中,如果在一个函数中声明一个基本类型的变量,这个变量在函数执行结束后会自动销毁。 而引用类型的变量名会保存在栈内存中,但是变量值会存储在堆内存中,引用类型的变量不会自动销毁,当没有引用变量引用它时,系统的垃圾回收机制会回收它,具体存储方式如下图所示:

图片描述

关于栈和堆,是一种简单的数据结构,不是本节实验的重点,这里只需要记住结论即可。

  • 赋值不同

基本类型的赋值相当于深拷贝,赋值后相当于又开辟了一个内存空间,如下所示:

let a = 100;
let b = a;
b = 101;
console.log(a, b); // 100 101

可以看出当 a 的值改变时并不影响 b 的值。

而引用类型的赋值是浅拷贝,当我们对对象进行操作时,其实操作的只是对象的引用,如下所示:

let obj = {
  name: "蓝桥",
};
let obj2 = obj;obj2.name = "蓝桥云课";
​
console.log(obj.name, obj2.name); //  蓝桥云课 蓝桥云课

可以看出,我们把 obj 的值赋值给 obj2,当 obj2 的值改变时,obj 的值也被改变。

这个时候面试官可能又接着问:那如何实现一个对象的深拷贝呢?

最简单的方式就是使用 JSON.stringifyJSON.parse 这组 API,如下所示:

JSON.stringify() 方法用于将 JavaScript 值转换为 JSON 字符串;JSON.parse() 方法将 JSON 字符串转化为 JavaScript 对象

let obj = {
  name: "蓝桥",
};
let obj2 = JSON.parse(JSON.stringify(obj));
obj2.name = "蓝桥云课";
​
console.log(obj.name, obj2.name); // 蓝桥 蓝桥云课

但是这种方式有些问题,当 obj 里面有函数或者 undefined 就会失效,如下所示:

let obj = {
  fn: function () {
    console.log("我是蓝桥");
  },
  name: undefined,
};
​
let obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj2); //{}

所以万全之策还是要用递归,如下所示:

function deep(obj) {
  let oo = {};
  for (const key in obj) {
    if (typeof obj[key] === "object") {
      oo[key] = deep(obj[key]);
    } else {
      oo[key] = obj[key];
    }
  }
​
  return oo;
}

上述代码的原理就是递归遍历对象的每个属性,分别赋值到一个新对象去。