javascript
理论
- 对象类型与原始值类型的不同之处?
- 对象类型的实际值存储在堆中,位置随机分配,对象的引用存储在栈中
- 原始值类型的值直接存储在栈中
- 对象类型的赋值是引用的拷贝,根据同一个引用访问到的是同一块堆空间
- 原始值类型的赋值是值的拷贝,访问到的是一个新的原始值
- typeof能否正常判断类型?有何局限
- 能判断一部分
- 对于原始值类型,除了null都可以正确判断
- 对于对象类型,除了function,都判断成object
- 将null, 判断成object
- 将函数判断成function
- == 与 === 区别
- == 是非严格比较,在判断两个值是否相等时会先将不同类型的值转换为同类型再比较
- === 是严格比较,不会进行类型转换,直接比较
- 模块化有什么优点?有哪几种方案
- 优点:
- 减小代码规模、便于开发管理
- 让代码工程化
- 避免变量命名冲突,全局变量污染
- 方案:
- CommonJS:同步的模块化方法,适用于服务端,实践者Nodejs,webpack
- AMD: 异步的模块化方法,适用于浏览器,定义模块时需要申明依赖关系,实践者:RequireJS
- CMD: 异步的模块化方法,适用于浏览器,定义模块时不需要申明依赖关系,需要用时再Require,实践者: SeaJS
- ES6的模块化方法
- 什么是Promise的链
- promise对象拥有的then、catch方法
- 其执行完成后的返回值仍然是promise对象,因此可以继续调用then、catch
- 这样不断的在后面调用then、catch,就形成了一个链
- Promise 构造函数执行和 then 函数执行有什么区别
- Promise构造函数的参数回调是同步立即执行的
- then的参数回调是异步执行
- 通过 new 的方式创建对象和通过字面量创建有什么区别
- new
- new 是通过执行构造函数来创建对象的
- 因此使用new就需要为构造函数的执行创建执行上下文,速度更慢
- 有构造函数就有原型对象,可以实现继承特性
- 字面量
- 字面量创建对象更方便,利于阅读
- 不需要创建执行上下文,速度更快
- 创建的对象比较简单,不利于继承(可以使用原型继承)
- 为什么0.1+0.2!==0.3?
- js中所以的数字都是以64位双浮点数来存储的
- 64位中,1位符号位,11位指数位决定表示范围,52位小数位决定可以表示的精度
- 当0.1转换成小数时,0.00011001100110011001100110011001100110011001100110011...
- 因此只有52位可以表示小数,因此需要截断,而截断时采取的策略是,截断位是1进位,是0舍去
- 而0.00011001100110011001100110011001100110011001100110011...截取后,被进位了因此偏大
- 0.1在计算机存储后表示的二进制是0.0001100110011001100110011001100110011001100110011010,值为0.10000000000000008882
- 0.2同理,但是0.2截取后是被舍去,结果偏小
- 0.2在计算机存储后表示的二进制是0.0011001100110011001100110011001100110011001100110011,值为0.19999999999999995559
- 二者相加后,总体偏大,二进制值为:0.0100110011001100110011001100110011001100110011001101,值为0.30000000000000004441
- 0.30000000000000004441是十进制的值,小数最多保留17位,因此0.30000000000000004 != 0.3
- 什么是执行栈?
- js代码的执行是在执行栈执行的
- 函数需要运行需要先将执行上下文加入执行栈,运行完成返回后才能出栈
- 执行栈底部永远是全局执行上下文,除非浏览器关闭,全局执行上下文才出栈
- 执行栈顶部永远是当前正在执行的执行上下文对应的代码
- 为什么js是单线程的?单线程优缺点是什么?
- js最初被设计出来是为了实现跟用户的交互,操作dom结点,工作比较单一,用不上多线程,如果使用多线程,线程之间不协作可能造成一些逻辑错误,需要使用线程同步等等技术来控制多线程的执行,增大了开发难度
- 优点是开发逻辑简单不用处理多线程会出现的线程同步问题
- 缺点是自身无法实现异步操作,需要借助浏览器来实现
事件
- 事件触发的过程是怎样的
- 事件触发后事件的传播分为三个阶段
- 捕获阶段
- 从外层HTML标签开始,到触发该事件的元素为止,依次传递事件,如果当前元素上有绑定对应捕获阶段的事件则执行(不包括目标元素)
- 事件目标处理函数
- 到达目标元素,便会执行绑定在此元素上的,与事件相应的函数,即事件目标处理函数阶段。
- 冒泡阶段
- 从触发这个事件的元素开始,到外层的HTML标签,依次传递该事件,如果当前元素上有绑定对应冒泡阶段的事件则执行(不包括目标元素)
- 之所以事件的传播分为捕获跟冒泡两种形式, 是因为网景跟IE提出的观点不一致,最后W3C将二者都采用了
- 通过addEventListener绑定事件时,传入第三个参数表示是否在捕获阶段触发,默认是false
- 下面输出是什么
<div id="div1">
<div id="div2">
<div id="div3">
</div>
</div>
</div>
<script>
const div1 = document.getElementById('div1')
const div2 = document.getElementById('div2')
const div3 = document.getElementById('div3')
div1.addEventListener('click', function () {
console.log(1);
})
div1.addEventListener('click', function () {
console.log(3);
}, false)
div1.addEventListener('click', function () {
console.log(2);
}, true)
div2.addEventListener('click', function () {
console.log(4);
})
div2.addEventListener('click', function () {
console.log(6);
}, false)
div2.addEventListener('click', function () {
console.log(5);
}, true)
div3.addEventListener('click', function () {
console.log(7);
})
div3.addEventListener('click', function () {
console.log(9);
}, false)
div3.addEventListener('click', function () {
console.log(8);
}, true)
div1.dispatchEvent(new Event('click'))
div2.dispatchEvent(new Event('click'))
div3.dispatchEvent(new Event('click'))
</script>

- new Event生成的事件对象中,bubbles属性默认为false,因此不会进行冒泡,所以冒泡阶段的函数没有执行
- 可以传入配置对象比如 new Event('click', {bubbles: true}),结果跟下方调用click一致
- 如果将dispatchEvent改成click
