【JS】面试八股文
类型
JavaScript 有哪些数据类型,它们的区别?
答:JavaScript
共有八种数据类型, 分别是 Undefined
、 Null
、 Boolean
、Number
、String
、Object
、Symbol
、BigInt
。
其中 Symbol
是ES6中新增的,BigInt
是 ES2020 中新增的。
Symbol
代表创建后独一无二且不可变的数据类型,它主要是为了解决可能出现的全局变量冲突的问题。
BigInt
是一种数字类型的数据, 它可以表示任意精度格式的整数,使用 BigInt
可以安全地存储和操作大整数, 即使这个数已经超出了Number
能够表示的安全整数范围。
其中,Object
被称为引用数据类型,其他被称为基础数据类型。
引用数据类型和基础数据类型有什么区别?
答:两种类型的区别在于存储位置的不同。
基础数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定。 如果存储在栈中, 将会影响程序运行的性能; 引用数据类型在栈中存储了指针, 该指针指向堆中该实体的起始地址。 当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
堆和栈的概念存在于数据结构和操作系统内存中,在数据结构中:
- 在数据结构中,栈中数据的存取方式为先进后出。
- 堆是一个优先队列, 是按优先级来进行排序的, 优先级可以按照大
小来规定。
在操作系统中,内存被分为栈区和堆区:
- 栈区内存由编译器自动分配释放, 存放函数的参数值, 局部变量的
值等。其操作方式类似于数据结构中的栈。 - 堆区内存一般由开发着分配释放, 若开发者不释放, 程序结束时可
能由垃圾回收机制回收。
为什么会有 BigInt 的提案?
答:JavaScript
中 Number.MAXSAFEINTEGER
表示最大安全数字,计算
结果是 9007199254740991, 即在这个数范围内不会出现精度丢失 (小数除外)。但是⼀旦超过这个范围,就会出现计算不准确的情况,
这在大数计算的时候不得不依靠⼀些第三方库进⾏解决, 因此官方提
出了 BigInt
来解决此问题。
数据类型检测的方式有哪些?
答:
typeof
:其中数组、对象、null
都会被判断为object
,其他判断都正确。instanceof
:可以正确判断对象的类型,其内部运行机制是判断在其原型链中能否找到该类型的原型。instanceof
只能正确判断引用数据类型,而不能判断基本数据类型。instanceof
运算符可以用来测试一个对象在其原型链中是否存在一个构造函数的prototype
属性。constructor
:有两个作用:一是判断数据的类型,二是对象实例通过constrcutor
对象访问它的构造函数。 需要注意, 如果创建一个对象来改变它的原型,constructor
就不能用来判断数据类型了。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
方法。
null 和 undefined 区别
答:首先 Undefined
和 Null
都是基本数据类型,这两个基本数据类型分别都只有一个值,就是 undefined
和 null
。
undefined
代表的含义是未定义,null
代表的含义是空对象。一般变量声明了但还没有定义的时候会返回undefined
,null
主要用于赋值给一些可能会返回对象的变量,作为初始化。undefined
在JavaScript
中不是一个保留字,这意味着可以使用undefined
来作为一个变量名, 但是这样的做法是非常危险的, 它会影响对undefined
值的判断。我们可以通过一些方法获得安全的
undefined
值,比如说void 0
。- 当对这两种类型使用
typeof
进行判断时,Null
类型化会返回object
, 这是一个历史遗留的问题。 - 当使用双等号对两种类型的值进行比较时会返回
true
,使用三个等号时会返回false
。
intanceof 操作符的实现原理及实现
instanceof 运算符用于判断构造函数的 prototype 属性是否出现
在对象的原型链中的任何位置。
如何获取安全的 undefined 值?
答:因为 undefined
是一个标识符, 所以可以被当作变量来使用和赋值,但是这样会影响 undefined
的正常判断。表达式 void
没有返回值,因此返回结果是 undefined
。void
并不改变表达式的结果,
只是让表达式不返回值。因此可以用 void 0
来获得 undefined
。
Object.is() 与比较操作符双等号、三等号 的区别?
答:使用双等号进行相等判断时,如果两边的类型不一致,则会进行强制类型转化后再进行比较。使用三等号(===)进行相等判断时,如果两边的类型不一致时,不会做强制类型准换,直接返回 false。
使用 Object.is
来进行相等判断时,一般情况下和三等号的判断相同,它处理了一些特殊的情况,比如 -0 和 +0 不再相等,两个 NaN是相等的。
如何判断一个对象是空对象
使用 JSON 自带的.stringify 方法来判断:
if(Json.stringify(Obj) == '{}' ){
console.log('空对象');
}
使用 ES6 新增的方法 Object.keys()来判断:
if(Object.keys(Obj).length < 0){
console.log('空对象');
}
什么是 JavaScript 中的包装类型?
答:在 JavaScript 中, 基本类型是没有属性和方法的, 但是为了便于操作基本类型的值, 在调用基本类型的属性或方法时 JavaScript 会在后台隐式地将基本类型的值转换为对象,如:在 访 问 'abc'.length
时 , JavaScript 将 'abc'
在 后 台 转 换 成String('abc')
,然后再访问其 length
属性。这就是包装类型。包装类型可以使用valueof
进行开箱,转成基本类型。
对象创建的方式有哪些?
答:一般使用字面量的形式直接创建对象, 但是这种创建方式对于创建大量相似对象的时候,会产生大量的重复代码。但 js 和一般的面向对象的语言不同,在 ES6 之前它没有类的概念。但是可以使用函数来进行模拟,从而产生出可复用的对象创建方式,常见的有以下几种:
(1)第一种是工厂模式,工厂模式的主要工作原理是用函数来封装创建对象的细节, 从而通过调用函数来达到复用的目的。 但是它有一个很大的问题就是创建出来的对象无法和某个类型联系起来, 它只是简单的封装了复用代码,而没有建立起对象和类型间的关系。
(2) 第二种是构造函数模式。 js 中每一个函数都可以作为构造函数,只要一个函数是通过 new 来调用的, 那么就可以把它称为构造函数。执行构造函数首先会创建一个对象, 然后将对象的原型指向构造函数的 prototype 属性,然后将执行上下文中的 this 指向这个对象,最后再执行