1. JS中的数据类型有哪些,他们的区别是什么?
-
知识点大纲
-
语言组织(示例)
要点:数量 → 种类 → 区别
JS中的数据类型主要有 8 种,分为两大类 基础数据类型 和 引用数据类型
基础数据类型中主要有 Number、String、Boolean、Null、Undefined、Symbol和BigInt
引用数据类型有Object,Object下又有一些内置的子类主要分为基础引用类型和集合类引用类型,基础引用类型比如基础类型包装类、Date、RegExp、单例全局对象window和Math等等,集合类引用对象有Array、Set、Map等等
两者的区别主要从三个方面体现:a. 存储方式不同 - 基础类型存放在栈内存中,引用类型存储在堆内存中 b. 复制方式不同 - 基础类型是复制一个副本,具有不可变性,引用类型复制的堆内存的地址引用,指向的还是同一个堆内存 c. 参数传递不同 - 参数传递本质还是复制一个变量的副本,所以区别类似于复制方式
2. 如何判断不同的数据类型
- 知识点大纲
- 语言组织(示例)
要点:方式的种类 → 每个种类的优缺点 → 通用的方式
判断数据类型的方式比较多,一般根据不同的场景采取对应的判断方式;
如果判断一个基础数据类型可以采用 typeof 的方式,它的返回结果为对应类型的字符串,但是 typeof 对于引用类型都是返回Object,判断的时候有两个例外,一个是null,null虽然是基础类型但是返回的还是object,另外一个是function,虽然function是引用类型,但是返回的是function
如果判断一个对象是否是属于某个类的实例,可以使用instanceof,格式为 A instanceof B,用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性
比较通用的一种方式是:Object.prototype.toString.call(),既可以检测基础数据类型,也可以检测引用类型,返回的格式为中括号内,第一个是object,第二个就是首字母大写的类型。之所以不能直接调用对象上的toString方法,是Array,Function等比较典型的方法都重写了toString方法,所以是调用的是Object对象原型上的toString方法。
- 代码运行
let a = 123; // typeof => number, Object.prototype => [object Number]
let b = 'string'; // typeof => string, Object.prototype => [object String]
let c = true;// typeof => boolean, Object.prototype => [object Boolean]
let d = null;// typeof => object, Object.prototype => [object Null]
let f = undefined;// typeof => undefined, Object.prototype => [object Undefined]
let g = Symbol();// typeof => symbol, Object.prototype => [object Symbol]
let e = BigInt(123);// typeof => bigint, Object.prototype => [object BigInt]
let h = [1,2,3];// typeof => object, Object.prototype => [object Array]
let i = {a:1,b:2};// typeof => object, Object.prototype => [object Object]
let k = function(){};// typeof => function, Object.prototype => [object Function]
- 推荐资料
JavaScript的数据类型及其检测:https://github.com/ljianshu/Blog/issues/4
3. 你刚刚有提到Symbol,那你在日常开发中有使用过么?
-
知识点大纲
-
语言组织(示例)
要点:提出背景 → 具有哪些特性 → 如何在项目中使用 三个方面递进回答
Symbol是在ES6中提出的第7种数据类型,也是一种基础数据类型。
(介入背景)因为对象的属性只能是字符串,所以我们在调用别人提供的对象时可能会涉及到一些属性的增加或修改而跟原本的属性产生命名冲突,也是基于这一背景,在ES6中提出了Symbol机制来保证属性的唯一性。
(介入特性)Symbol 类型的变量都是独一无二的,可以保证不会与其他属性名产生冲突,
(引出场景)正是因为它这种不可变的特性,在我们日常开发中主要分为两种场景:业务开发场景中使用,去声明一个枚举类型对象或者全局常量等,保证常量属性的唯一性,另一种场景是在日常组件开发中,使用Symbol去定义一些组件的ID值及状态值等。
4. 0.1+0.2不等于0.3,你是怎么理解的呢
-
知识点大纲
-
语言组织(示例)
从 遵循的标准 → 标准导致的问题 → JS中提出的方案 → 最后问题的答案
这个涉及到JS的数值类型遵循的算术标准:IEEE 754 二进制浮点数算术标准,在JS中使用的是双精度浮点数,即用64位表示数值。这64位又被分成了3个域,符号位、指数域和尾数域。从右到左分别编号063的话,编码051就表示尾数域,编码52~62表示指数域,编码63就表示符号位。
由这种表示方式就导致了两个问题:精度问题和大小问题,精度问题由尾数域导致,它只有52位去表示精度,像0.1、0.2这种无限循环小数就会存在精度丢失问题,大小问题则是由指数域导致的,大于等于2的1024次方的数值就无法表示了,也就出现了数值中的特殊数值Infinity。这两种问题并不是JS中特有的,而是使用IEEE 754 标准浮点数表示法的语言都存在的问题。
在JS中主要有两种解决方案,一个是ES2020提出的 BigInt数据类型用来存储计算大数据,没有精度限制;另一种是机器精度,即使存在误差,但是只要在最小误差内就可以忽略不计,这个精度大概是2的-52次方,也就是JS能表示的最小精度值,在ES6中,把这个值放到了Number.EPSILON常量中。
- 资料(IEEE754标准、指数偏移值计算详情可参考以下链接)
维基百科:https://zh.wikipedia.org/wiki/IEEE_754
百度文库:https://wenku.baidu.com/view/b50d16c9a6c30c2259019ede.html?wkts=1704806640422&bdQuery=IEEE+754
5. 说一下你了解的数组方法有哪些?
-
知识点大纲
-
语言组织(示例)
要点: 产生数组 → 操作数组 → 遍历数组,在 操作数组 部分又分两个方向回答:会改变原数组和不会改变原数组,切忌想到哪个说哪个,毫无逻辑感
常用到的数组方法,主要涉及到三个方面的:创建数组类、操作数组类和遍历数组类。
创建数组类的主要有:Array.of()、Array.from(),这两个都是ES6中新增的数组方法,Array.of()用于将一组数值转换为数组,Array.from()用于将类数组对象转换为数组。
操作数组类的主要 会改变原数组类 和 不会改变原数组类两种,会改变原数组类的涉及到基本都是增删改相关的函数:push/pop、unshift/shift、copyWithin、fill、splice、reverse、sort等,不会改变原数组的主要是查找拼接相关的函数:indexOf、lastIndexOf、includes、concat、join、slice、toString等。
还有一些对数组的遍历操作:forEach、map、some、every、filter、reduce、find等等
- 推荐链接
数组API及常见排序算法:https://blog.csdn.net/weixin_41305441/article/details/119008708