当前位置: 首页 > news >正文

JS面试常见问题——数据类型篇

这几周在进行系统的复习,这一篇来说一下自己复习的JS数据结构的常见面试题中比较重要的一部分

文章目录

    • 一、JavaScript有哪些数据类型
    • 二、数据类型检测的方法
      • 1. typeof
      • 2. instanceof
      • 3. constructor
      • 4. Object.prototype.toString.call()
      • 5. type null会被判断为Object,为什么
      • 6. typeof NaN的结果是什么
    • 三、判断数组的方式有哪些
      • 1. Object.prototype.toString.call()
      • 2. 通过原型链判断
      • 3. 通过ES6的Array.isArray()做判断
      • 4. 通过instanceof判断
      • 5. 通过Array.prototype.isPrototypeOf()
    • 四、null和undefined的区别
    • 五、instanceof操作符的实现原理及实现
    • 六、为什么0.1+0.2 !== 0.3,如何让其相等
      • 1. 原因
      • 2. 如何解决
    • 七、==操作符的强制类型转换规则
    • 八、Object.is()与比较操作符“=== ”、“ ==”的区别
    • 九、其他值到字符串的转换规则
    • 十、其他值到数字值的转换规则
    • 十一、其他值到布尔类型的值的转换规则
    • 十二、isNaN和Number.isNaN函数的区别
    • 十三、JavaScript中如何进行隐式类型转换
      • 1. ToPrimitive
      • 2. 隐式转换规则
      • 3. +操作符什么时候用于字符串拼接

一、JavaScript有哪些数据类型

八种:Number String Boolean Null undefined Object Symbol BigInt
Symbol & BigInt 是ES6新增的数据类型

  • Symbol 代表创建后独一无二且不可变的数据类型;主要是为了解决可能出现全局变量冲突的问题
  • BigInt是一种数字类型,可以表示任意精度格式的整数,使用BigInt可以安全地存储和操作大整数,即使这个数超出Number能够表示的安全整数范围

分类:原始数据类型 & 引用数据类型
栈:Number String Boolean Null Undefined(原始数据类型)
堆:Object(引用数据类型)(对象、数组、函数)
两种类型的区别在于存储位置的不同:

  • 原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;
  • 引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

数据结构和操作系统中
堆和栈的概念存在于数据结构和操作系统内存中,在数据结构中:
● 在数据结构中,栈中数据的存取方式为先进后出。
● 堆是一个优先队列,是按优先级来进行排序的,优先级可以按照大小来规定。
在操作系统中,内存被分为栈区和堆区:
● 栈区内存由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
● 堆区内存一般由开发着分配释放,若开发者不释放,程序结束时可能由垃圾回收机制回收。

二、数据类型检测的方法

1. typeof

注:数组、对象、null都会被判断为Object

2. instanceof

可以正确判断对象的类型,不能判断基本数据类型;可以用来测试一个对象在其原型链中是否存在一个构造函数的prototype属性
内部运行机制是判断在其原型链中能否找到该类型的原型

3. constructor

判断数据的类型;对象实例通过constructor对象访问它的构造函数;如果创建一个对象来改变他的原型,constructor就不能用来判断数据类型了

4. Object.prototype.toString.call()

使用 Object 对象的原型方法 toString 来判断数据类型

同样是检测对象obj调用toString方法,obj.toString()的结果和Object.prototype.toString.call(obj)的结果不一样,这是为什么?
这是因为toString是Object的原型方法,而Array、function等类型作为Object的实例,都重写了toString方法。不同的对象类型调用toString方法时,根据原型链的知识,调用的是对应的重写之后的toString方法(function类型返回内容为函数体的字符串,Array类型返回元素组成的字符串…),而不会去调用Object上原型toString方法(返回对象的具体类型),所以采用obj.toString()不能得到其对象类型,只能将obj转换为字符串类型;因此,在想要得到对象的具体类型时,应该调用Object原型上的toString方法。

5. type null会被判断为Object,为什么

在 JavaScript 第一个版本中,所有值都存储在 32 位的单元中,每个单元包含一个小的 类型标签(1-3 bits) 以及当前要存储值的真实数据。类型标签存储在每个单元的低位中,共有五种数据类型:

000: object - 当前存储的数据指向一个对象。
1: int - 当前存储的数据是一个 31 位的有符号整数。
010: double - 当前存储的数据指向一个双精度的浮点数。
100: string - 当前存储的数据指向一个字符串。
110: boolean - 当前存储的数据是布尔值。
有两种特殊数据类型:
● undefined的值是 (-2)30(一个超出整数范围的数字);
● null 的值是机器码 NULL 指针(null 指针的值全是 0)
在 JavaScript 中二进制前三位都为 0 的话会被判断为 object 类型, null 的二进制表示是全 0,自然前三位也是 0,所以执行 typeof 时会返回 object。

6. typeof NaN的结果是什么

返回的结果:number
NaN 指“不是一个数字”(not a number),NaN 是一个“警戒值”(sentinel value,有特殊用途的常规值),用于指出数字类型中的错误情况,即“执行数学运算没有成功,这是失败后返回的结果”。
NaN 是一个特殊值,它和自身不相等,是唯一一个非自反(自反,reflexive,即 x === x 不成立)的值。而 NaN !== NaN 为 true。

三、判断数组的方式有哪些

1. Object.prototype.toString.call()

Object.prototype.toString.call(obj).slice(8,-1) === 'Array';

2. 通过原型链判断

obj.__proto__ === Array.prototype;

3. 通过ES6的Array.isArray()做判断

4. 通过instanceof判断

5. 通过Array.prototype.isPrototypeOf()

四、null和undefined的区别

undefined代表的含义是未定义,当一个变量没有任何数据时也是undefined,undefined是原始数据类型之一,可以直接把undefined赋值给变量或函数返回;被迫的替代方案
null是空对象,需要主动使用,没有声明不会出现;空
判断null和undefined时需要使用严格判断(===)

五、instanceof操作符的实现原理及实现

instanceof 运算符用于判断构造函数的 prototype 属性是否出现在对象的原型链中的任何位置。

function myInstanceof(left, right) {// 获取对象的原型let proto = Object.getPrototypeOf(left)// 获取构造函数的 prototype 对象let prototype = right.prototype; // 判断构造函数的 prototype 对象是否在对象的原型链上while (true) {if (!proto) return false;if (proto === prototype) return true;// 如果没有找到,就继续从其原型上找,Object.getPrototypeOf方法用来获取指定对象的原型proto = Object.getPrototypeOf(proto);}
}

六、为什么0.1+0.2 !== 0.3,如何让其相等

1. 原因

计算机是通过二进制的方式存储数据的,所以计算机计算0.1+0.2的时候,实际上是计算的两个数的二进制的和。0.1的二进制是0.0001100110011001100…(1100循环),0.2的二进制是:0.00110011001100…(1100循环),这两个数的二进制都是无限循环的数。
但是在 JavaScript 中只有一种数字类型:Number,它的实现遵循IEEE 754标准,使用64位固定长度来表示,也就是标准的double双精度浮点数。在二进制科学表示法中,双精度浮点数的小数部分最多只能保留52位,再加上前面的1,其实就是保留53位有效数字,剩余的需要舍去,遵从“0舍1入”的原则。
根据这个原则,0.1和0.2的二进制数相加,再转化为十进制数就是:0.30000000000000004。
在这里插入图片描述

  • 第一部分(蓝色):用来存储符号位(sign),用来区分正负数,0表示正数,占用1位
  • 第二部分(绿色):用来存储指数(exponent),占用11位
  • 第三部分(红色):用来存储小数(fraction),占用52位

2. 如何解决

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3

七、==操作符的强制类型转换规则

  1. 一个布尔值,将其转换为数字比较
  2. 一个字符串,一个数字、布尔值或null,将字符串转换为数字比较。
  3. 一个对象,一个字符串、数字或符号,将对象转换为原始值比较。
    对象转换为原始值的规则如下:
  1. 如果对象有valueOf方法并返回基本类型的值,则使用该值进行比较。
  2. 如果valueOf方法返回的仍然是对象,则调用对象的toString方法,并使用返回的字符串进行比较。
  3. 如果对象没有valueOf和toString方法,或者返回的不是基本类型的值,则抛出TypeError异常。
  1. 一个null,一个undefined,则相等。
  2. 一个NaN,一个不是NaN,则相等
  3. 一个数字0,一个字符串且内容为非空,则将数字0转换为字符串再进行比较。
  4. 其他情况下,将操作数都转换为数字再进行比较。
    需要注意的是,如果两个都是对象,则比较的是它们的引用是否相等,不会进行强制类型转换。

八、Object.is()与比较操作符“=== ”、“ ==”的区别

  1. 使用双等号(==)进行相等判断时,如果两边的类型不一致,则会进行强制类型转化后再进行比较。
  2. 使用三等号(===)进行相等判断时,如果两边的类型不一致时,不会做强制类型准换,直接返回 false。
  3. 使用 Object.is 来进行相等判断时,一般情况下和三等号的判断相同,它处理了一些特殊的情况,比如 -0 和 +0 不再相等,两个 NaN 是相等的。

九、其他值到字符串的转换规则

  1. Null 和 Undefined 类型 ,null 转换为 “null”,undefined 转换为 “undefined”,
  2. Boolean 类型,true 转换为 “true”,false 转换为 “false”。
  3. Number 类型的值直接转换,不过那些极小和极大的数字会使用指数形式。
  4. Symbol 类型的值直接转换,但是只允许显式强制类型转换,使用隐式强制类型转换会产生错误。
  5. 对普通对象来说,除非自行定义 toString() 方法,否则会调用 toString()(Object.prototype.toString())来返回内部属性 [[Class]] 的值,如"[object Object]"。如果对象有自己的 toString() 方法,字符串化时就会调用该方法并使用其返回值。

十、其他值到数字值的转换规则

  1. Undefined 类型的值转换为 NaN。
  2. Null 类型的值转换为 0。
  3. Boolean 类型的值,true 转换为 1,false 转换为 0。
  4. String 类型的值转换如同使用 Number() 函数进行转换,如果包含非数字值则转换为 NaN,空字符串为 0。
  5. Symbol 类型的值不能转换为数字,会报错。
  6. 对象(包括数组)会首先被转换为相应的基本类型值,如果返回的是非数字的基本类型值,则再遵循以上规则将其强制转换为数字。

为了将值转换为相应的基本类型值,抽象操作 ToPrimitive 会首先(通过内部操作 DefaultValue)检查该值是否有valueOf()吗方法。如果有并且返回基本类型值,就使用该值进行强制类型转换。如果没有就使用 toString() 的返回值(如果存在)来进行强制类型转换。
如果 valueOf() 和 toString() 均不返回基本类型值,会产生 TypeError 错误。

十一、其他值到布尔类型的值的转换规则

假值: undefined null false +0、-0 和 NaN “”
假值的布尔强制类型转换结果为false;从逻辑上说,假值表以外的应该都是真值

十二、isNaN和Number.isNaN函数的区别

  • 函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true,会影响 NaN 的判断。
  • 函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

十三、JavaScript中如何进行隐式类型转换

1. ToPrimitive

JavaScript 中每个值隐含的自带的方法,用来将值 (无论是基本类型值还是对象)转换为基本类型值。如果值为基本类型,则直接返回值本身;如果值为对象,

// @obj 需要转换的对象 
// @type 期望的结果类型
ToPrimitive(obj,type)

type的值为number或者string。
(1)当type为number时规则如下:
● 调用obj的valueOf方法,如果为原始值,则返回,否则下一步;
● 调用obj的toString方法,后续同上;
● 抛出TypeError 异常。
(2)当type为string时规则如下:

  • 调用obj的toString方法,如果为原始值,则返回,否则下一步;
  • 调用obj的valueOf方法,后续同上;
  • 抛出TypeError异常。

默认情况下:

  • 如果对象为 Date 对象,则type默认为string;
  • 其他情况下,type默认为number。

Date 以外的对象,转换为基本类型的大概规则可以概括为一个函数:

var objToNumber = value => Number(value.valueOf().toString())
objToNumber([]) === 0
objToNumber({}) === NaN

2. 隐式转换规则

隐式类型转换主要发生在+、-、*、/以及==、>、<这些运算符之间

  1. +操作符的两边有至少一个string类型变量时,两边的变量都会被隐式转换为字符串;其他情况下两边的变量都会被转换为数字。
  2. -、*、\操作符NaN也是一个数字
  3. ==操作符两边的值都尽量转成number
  4. <>如果两边都是字符串,则比较字母表顺序;其他情况下,转为数字再比较;对象会被ToPrimitive转换为基本类型再进行转换

3. +操作符什么时候用于字符串拼接

如果 + 的其中一个操作数是字符串(或者通过以上步骤最终得到字符串),则执行字符串拼接,否则执行数字加法
除了加法的运算符来说,只要其中一方是数字,那么另一方就会被转为数字。
|| 和 && 操作符的返回值

相关文章:

  • 传输层:udp与tcp协议
  • 【递归、搜索与回溯】专题三 穷举vs暴搜vs回溯vs剪枝
  • Python获取网易云音乐的评论
  • Java-前置基础
  • Kafka 入门指南与一键部署
  • S5P6818_驱动篇(24)UART驱动
  • IoT/HCIP实验-4/单片机基础实验(LCD/LED/按键操作/GPIO/EXTI中断服务)
  • untiy 模拟人物在街道走路和跑步
  • Java中==和equals的区别
  • 理解JavaScript中map和parseInt的陷阱:一个常见的面试题解析
  • sklearn 和 pytorch tensorflow什么关系
  • 12.vite,webpack构建工具
  • 【Linux 学习计划】-- 简易版shell编写
  • 刷题记录(7)二叉树
  • 六、【ESP32开发全栈指南:深入解析ESP32 IDF中的WiFi AP模式开发】
  • 欧拉定理和费马定理
  • Gerrit+repo管理git仓库,如果本地有新分支不能执行repo sync来同步远程所有修改,会报错
  • 飞牛使用Docker部署Tailscale 内网穿透教程
  • 【Linux基础知识系列】第十四篇-系统监控与性能优化
  • 校招 Java 面试基础题目解析学习指南含新技术实操要点
  • 中国企业500强中国铁建/太原高级seo主管
  • 怎么把网站建设推广出去/阿里云搜索
  • 织梦cms如何做网站/什么叫优化关键词
  • 山西网站建设开发/下列关于seo优化说法不正确的是
  • 树莓派用来做网站/企业软文怎么写
  • 建站什么程序好/seo指的是什么意思