关键概念
this
指代当前代码运行时的上下文
- 箭头函数:继承作用域链上一层上下文
new
调用函数:指向new出来的对象call/bind/apply
:指向绑定的对象apply、call
的实现原理 在传入的函数上创建一个临时方法,传入剩余参数调用此方法,最后删除临时创建的方法bind
的实现原理 返回一个新函数,包裹了apply、call
类似的处理方式
- 全局函数:指向
window
- 对象上的函数,指向调用此函数的对象
闭包
什么是作用域?
ES5 中只存在两种作用域:全局作用域和函数作用域。在 JavaScript 中,我们将作用域定义为一套规则,这套规则用来管理引擎如何在当前作用域以及嵌套子作用域中根据标识符名称进行变量(变量名或者函数名)查找
什么是作用域链?
- 当访问一个变量时,编译器在执行这段代码时,会首先从当前的作用域中查找是否有这个标识符,如果没有找到,就会去父作用域查找,如果父作用域还没找到继续向上查找,直到全局作用域为止
- 作用域链,就是有当前作用域与上层作用域的一系列变量对象组成,它保证了当前执行的作用域对符合访问权限的变量和函数的有序访问。
闭包是怎么产生的
当前环境中存在指向父级作用域的引用,即:函数中返回函数,内部函数有对外部函数的变量引用。
什么是闭包
闭包是一种特殊的对象,它由两部分组成:执行上下文(代号 A),以及在该执行上下文中创建的函数 (代号 B),当 B 执行时,如果访问了 A 中变量对象的值,那么闭包就会产生,且在 Chrome 中使用这个执行上下文 A 的函数名代指闭包。
AST抽象语法树
- 词法分析:
scanner
- 读取代码,按照规则把他们变成一个个标识tokens,遇到空格,操作符,或者特殊符号的时候,它会认为一个token已经完成l
- 移除空白符,注释
- 最后代码变成一个token列表
- 语法分析:解析器 它会将词法分析出来的数组转化成树形的表达形式
- 同时验证语法,语法有错误的话则抛出错误
- 生成树的时候,解析器会删除一些没必要的标识tokens(比如不完整的括号)
浅拷贝和深拷贝
- 浅拷贝:只复制了对象的的引用,新旧对象指向同一个引用,数据同步更新 可通过
Object.assign
或者扩展运算符进行浅拷贝 - 深拷贝:完全复制了一个全新对象,新旧对象无关联
JSON.parse(JSON.stringify(obj))
:性能高,但存在undefined
、函数、循环引用时无法拷贝- 递归复制:递归复制每一项变量。
0.1 + 0.2 !== 0.3
js浮点数计算有误差,某些情况下没有误差,但是为了避免误差,不用浮点数进行运算,应该转成整数计算再还原为小数。
a.b.c.d
和 a['b']['c']['d']
,哪个性能更高?
a.b.c.d
比 a['b']['c']['d']
性能高点,因为[ ]里面有可能是字符串,有可能是变量,至少多一次判断,而a.b.c.d是直接取用该字符串当作属性名的
ES6 代码转成 ES5 代码的实现思路是什么?
Babel实现:
- 将代码字符串解析成抽象语法树,即所谓的
AST
- 对
AST
进行处理,在这个阶段可以对 ES6 代码进行相应转换,即转成 ES5 代码 - 根据处理后的
AST
再生成代码字符串
isNaN 和 Number.isNaN 函数的区别?
- 函数
isNaN
接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回true
,因此非数字值传入也会返回true
,会影响NaN
的判断。 - 函数
Number.isNaN
会首先判断传入参数是否为数字,如果是数字再继续判断是否为NaN
,不会进行数据类型的转换,这种方法对于NaN
的判断更为准确。
包装类型
在 JavaScript 中,基本类型是没有属性和方法的,但是为了便于操作基本类型的值,在调用基本类型的属性或方法时 JavaScript 会在后台隐式地将基本类型的值转换为对象,如:
javascript
const a = "abc";
a.length; // 3
a.toUpperCase(); // "ABC"
在访问'abc'.length
时,JavaScript
将'abc'
在后台转换成String('abc')
,然后再访问其length
属性。