目录
1 数据类型基础
1.1 JS内置类型
1.2 null和undefined区别
1.3 null是对象吗?为什么?
1.4 '1'.toString()为什么可以调用?
1.5 0.1+0.2为什么不等于0.3?如何让其相等
1.6 如何理解BigInt
1.7 JS 整数是怎么表示的
1.8 Number() 的存储空间是多大?如果后台发送了一个超过最大自己的数字怎么办
2 数据类型检测
2.1 typeof类型判断
2.2 typeof 于 instanceof 区别
2.3 Object.is和===的区别
2.4 总结
3 数据类型转换
3.1 转化规则
3.2 转Boolean
3.3 对象转原始类型是根据什么流程运行的
3.4 如何让if(a == 1 &&a == 2)条件成立
3.5 四则运算符
3.6 比较运算符
3.7 [] == ![]结果是什么?为什么?
3.8 == 和 ===有什么区别
4 闭包
4.1 闭包产生的原因
4.2 闭包有哪些表现形式
4.3 如何解决下面的循环输出问题
4.4 闭包的几种使用场景
5 原型和原型链链
5.1 原型/构造函数/实例
5.2 原型对象和构造函数有何关系
5.3 能不能描述一下原型链
6 继承
6.1 方式1: 借助call
6.2 方式2: 借助原型链
6.3 方式3:将前两种组合
6.4 方式4: 组合继承的优化1
6.5 方式5(最推荐使用): 组合继承的优化2
6.6 ES6的extends被编译后的JavaScript代码
6.7 从设计思想上谈谈继承本身的问题
6.8 继承-简版
7 this
8 内存机制
9 执行上下文
10 变量提升
11 模块化
12 异步编程
12.1 浏览器中的Event loop
12.2 Node 中的 Event loop
12.3 实现一个Promise A+ 规范
12.4 setTimeout、Promise、Async / Await 的区别
12.5 setTimeout(fn, 0)多久才执行,Event Loop
12.6 async原理
13 内存泄露
13.1 Chrome devTools查看内存情况
13.2 内存泄漏的场景
14 垃圾回收机制
15 深浅拷贝
16 对象的几种创建方式
16.1 工厂模式,创建方式
16.2 构造函数模式
16.3 使用原型模式
16.4 组合使用构造函数模式和原型模式
16.5 动态原型模式
17 数组相关
17.1 数组常用方法
17.2 Array(3)和Array(3, 4)的区别?
17.3 请创建一个长度为100,值都为1的数组
17.4 请创建一个长度为100,值为对应下标的数组
17.5 如何转化类数组成数组
17.6 forEach中return有效果吗?如何中断forEach循环?
17.7 JS判断数组中是否包含某个值
17.8 JS中flat---数组扁平化
18 操作DOM
18.1 说说有几种类型的DOM节点
18.2 操作DOM节点方法
19 Ajax总结
19.1 Ajax 有那些优缺点
19.2 关于http,XMLHttpRequest,Ajax的关系
19.3 XMLHttpRequest的发展历程是怎样的?
19.4 使用XMLHttpRequest封装一个get和post请求
20 定时器
20.1 setInterval存在哪些问题?
20.2 链式调用setTimeout对比setInterval
20.3 实现比 setTimeout 快 80 倍的定时器
22.4 说一下requestAnimationFrame
22.5 requestAnimationFrame对比setTimeout
21 谈谈你对for in/for of的理解
22 JavaScript 实现对上传图片的压缩?
-
1 数据类型基础
-
1.1 JS内置类型
JS
中分为七种内置类型,七种内置类型又分为两大类型:基本类型和对象(Object
)。- 基本类型有七种:
null
,undefined
,boolean
,number
,string
,symbol
,bigint
BigInt
是ES10
新增的数据类型Symbol
代表独一无二的值,最大的用法是用来定义对象的唯一属性名。BigInt
可以表示任意大小的整数。
- 其中
JS
的数字类型是浮点类型的,没有整型。并且浮点类型基于IEEE 754
标准实现,在使用中会遇到某些 Bug。NaN
也属于number
类型,并且NaN
不等于自身。 - 对于基本类型来说,如果使用字面量的方式,那么这个变量只是个字面量,只有在必要的时候才会转换为对应的类型。
- 引用数据类型:
- 对象
Object
(包含普通对象-Object
,数组对象-Array
,正则对象-RegExp
,日期对象-Date
,数学函数-Math
,函数对象-Function
) -
let a = 111 // 这只是字面量,不是 number 类型 a.toString() // 使用时候才会转换为对象类型
对象(
Object
)是引用类型,在使用过程中会遇到浅拷贝和深拷贝的问题。 -
let a = {name: 'FE', } let b = a b.name = 'EF' console.log(a.name) // EF
说出下面运行的结果,解释原因。
-
function test(person) {person.age = 26person = {name: 'hzj',age: 18,}return person } const p1 = {name: 'fyq',age: 19, } const p2 = test(p1) console.log(p1) // ->? console.log(p2) // ->?// 结果: p1 = {name: 'fyq',age: 26, } p2 = {name: 'hzj',age: 18, }
原因: 在函数传参的时候传递的是对象在堆中的内存地址值,test函数中的实参person是p1对象的内存地址,通过调用
person.age = 26
确实改变了p1的值,但随后person
变成了另一块内存空间的地址,并且在最后将这另外一份内存空间的地址返回,赋给了p2。
-
-
1.2 null和undefined区别
Undefined
类型只有一个值,即undefined
。当声明的变量还未被初始化时,变量的默认值为undefined
。用法
- 变量被声明了,但没有赋值时,就等于
undefined
。 - 调用函数时,应该提供的参数没有提供,该参数等于
undefined
。 - 对象没有赋值的属性,该属性的值为
undefined
。 - 函数没有返回值时,默认返回
undefined
Null
类型也只有一个值,即null
。null
用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象。用法
- 作为函数的参数,表示该函数的参数不是对象。
- 作为对象原型链的终点
-
1.3 null是对象吗?为什么?
结论: null
不是对象。
解释: 虽然
typeof null
会输出 object,但是这只是 JS 存在的一个悠久 Bug。在 JS 的最初版本中使用的是 32 位系统,为了性能考虑使用低位存储变量的类型信息,000 开头代表是对象然而 null 表示为全零,所以将它错误的判断为 object 。
-
1.4 '1'.toString()为什么可以调用?
其实在这个语句运行的过程中做了这样几件事情
var s = new Object('1')s.toString()s = null
- 第一步: 创建Object类实例。注意为什么不是String ? 由于Symbol和BigInt的出现,对它们调用new都会报错,目前ES6规范也不建议用new来创建基本类型的包装类。
- 第二步: 调用实例方法。
- 第三步: 执行完方法立即销毁这个实例。
整个过程体现了
基本包装类型
的性质,而基本包装类型恰恰属于基本数据类型
,包括Boolean, Number和String。
-
1.5 0.1+0.2为什么不等于0.3?如何让其相等
0.1
和0.2
在转换成二进制后会无限循环,由于标准位数的限制后面多余的位数会被截掉,此时就已经出现了精度的损失,相加后因浮点数小数位的限制而截断的二进制数字在转换为十进制就会变成0.30000000000000004
我们都知道计算机时是通过二进制来进行计算的,即 0
和 1
- 就拿
0.1 + 0.2
来说,0.1
表示为0.0001100110011001...
,而0.2
表示为0.0011001100110011...
- 而在二进制中
1 + 1 = 10
,所以0.1 + 0.2 = 0.0100110011001100...
- 转成
10
进制就近似表示为0.30000000000000004
简单来说就是,浮点数转成二进制时丢失了精度,因此在二进制计算完再转回十进制时可能会和理论结果不同
1. ES6提供的Number.EPSILON方法
function isEqual(a, b) {return Math.abs(a - b) < Number.EPSILON
}
console.log(isEqual(0.1 + 0.2, 0.3))
// true
Number.EPSILON
的实质是一个可以接受的最小误差范围,一般来说为 Math.pow(2, -52)
2. 乘以一个10的幂次方
把需要计算的数字乘以10
的n
次方,让数值都变为整数,计算完后再除以10
的n
次方,这样就不会出现浮点数精度丢失问题
(0.1 * 10 + 0.2 * 10) / 10 == 0.3
//true
-
1.6 如何理解BigInt
什么是BigInt?
BigInt
是一种新的数据类型,用于当整数值大于Number数据类型支持的范围时。这种数据类型允许我们安全地对大整数执行算术操作,表示高分辨率的时间戳,使用大整数id,等等,而不需要使用库。
为什么需要BigInt?
在JS中,所有的数字都以双精度64位浮点格式表示,那这会带来什么问题呢?
这导致JS中的Number无法精确表示非常大的整数,它会将非常大的整数四舍五入,确切地说,JS中的
Number
类型只能安全地表示-9007199254740991(-(2^53-1))和9007199254740991((2^53-1))
,任何超出此范围的整数值都可能失去精度。
console.log(999999999999999)
//=>10000000000000000
同时也会有一定的安全性问题:
9007199254740992 === 9007199254740993
// → true 居然是true!
如何创建并使用BigInt?
要创建BigInt
,只需要在数字末尾追加n
即可
console.log(9007199254740995n)
// → 9007199254740995n
console.log(9007199254740995)
// → 9007199254740996
另一种创建BigInt
的方法是用BigInt()
构造函数
BigInt('9007199254740995 ')
// → 9007199254740995n
简单使用如下:
10n + 20n
// → 30n
10n - 20n
// → -10n
+10n
// → TypeError: Cannot convert a BigInt value to a number
-10n
// → -10n
10n * 20n
// → 200n
20n / 10n
// → 2n
23n % 10n
// → 3n
10n ** 3n
// → 1000n
const x = 10n
++x
// → 11n
--x
// → 9n
console.log(typeof x)
//"bigint "
值得警惕的点
BigInt
不支持一元加号运算符, 这可能是某些程序可能依赖于 + 始终生成Number
的不变量,或者抛出异常。另外,更改+
的行为也会破坏asm.js
代码。
因为隐式类型转换可能丢失信息,所以不允许在bigint
和 Number
之间进行混合操作。当混合使用大整数和浮点数时,结果值可能无法由BigInt
或Number
精确表示。
10 + 10n
// → TypeError
不能将BigInt
传递给Web api
和内置的 JS 函数,这些函数需要一个 Number 类型的数字。尝试这样做会报TypeError错误。
Math.max(2n, 4n, 6n)
// → TypeError
当 Boolean
类型与 BigInt
类型相遇时,BigInt
的处理方式与Number
类似,换句话说,只要不是0n
,BigInt
就被视为truthy
的值。
if (0n) {//条件判断为false
}
if (3n) {//条件为true
}
- 元素都为BigInt的数组可以进行sort。
BigInt
可以正常地进行位运算,如|
、&
、<<
、>>
和^
-
浏览器兼容性
caniuse的结果:
其实现在的兼容性并不怎么好,只有chrome67、firefox、Opera这些主流实现,要正式成为规范,其实还有很长的路要走
-
1.7 JS 整数是怎么表示的
通过 Number 类型来表示,遵循 IEEE754 标准,通过 64 位来表示一个数字,(1 + 11 + 52),最大安全数字是 Math.pow(2, 53) - 1,对于 16 位十进制。(符号位 + 指数位 + 小数部分有效位)
-
1.8 Number() 的存储空间是多大?如果后台发送了一个超过最大自己的数字怎么办
Math.pow(2, 53) ,53 为有效数字,会发生截断,等于 JS 能支持的最大数字。
-
2 数据类型检测