ES6+✅
JavaScript、ECMAScript、BOM、DOM、Node.js 之间是什么关系?
答案
- ECMAScript 是 JavaScript 的标准化规范,定义了语法、数据类型、控制流等,是 JS 的“语言核心”。
- JavaScript 是实现了 ECMAScript 标准的编程语言,实际开发中还包含 BOM、DOM 等能力。
- BOM(浏览器对象模型)是浏览器提供的 API,如 window、location、history 等,允许 JS 操作浏览器环境。
- DOM(文档对象模型)是浏览器提供的 API,允许 JS 操作网页结构和内容。
- Node.js 是基于 V8 引擎的 JS 运行时,让 JS 能在服务器端运行,提供文件、网络等 API,不包含 BOM/DOM。
答案解析
JS 语言核心由 ECMAScript 定义,BOM/DOM/Node.js 提供不同运行环境的扩展能力。
面试官视角
- 核心考察点:能否区分 JS 语言核心与运行环境
- 评分标准:
- 差:混淆 ECMAScript、BOM、DOM
- 优:能清晰描述各自作用和关系
递归和尾递归是什么概念?
答案
- 递归:函数调用自身,通常用于分解问题。每次递归会创建新的调用栈帧,若无终止条件会导致栈溢出。
- 尾递归:递归调用是函数的最后一步,返回递归结果,无需保留当前帧。理论上可被优化为循环,避免栈溢出(JS 目前主流引擎未实现优化)。
// 普通递归 function factorial (n) { if (n === 0) return 1 return n * factorial(n - 1) } // 尾递归 function factorialTail (n, result = 1) { if (n === 0) return result return factorialTail(n - 1, n * result) }
答案解析
尾递归可优化性能,减少栈空间消耗,但 JS 引擎实际支持有限。
面试官视角
- 核心考察点:能否区分递归与尾递归
- 评分标准:
- 差:只会写递归
- 优:能举例说明尾递归优化原理
JS 严格模式为什么禁用 with 语句?
答案
严格模式禁用 with 语句,原因有三:
- 性能问题:with 让作用域链不确定,阻碍 JS 引擎优化。
- 可读性差:with 会引入命名冲突,代码难以维护。
- 易出错:with 可能导致变量意外变为全局变量或覆盖局部变量,增加 bug 风险。
const person = { name: 'Alice', age: 25 } function updatePerson (person) { // with (person) { name = 'Bob' // 实际创建了全局变量 name // } } updatePerson(person) console.log(window.name) // 'Bob'
答案解析
with 破坏作用域链和变量查找规则,易引发难以排查的 bug,严格模式下直接报错。
面试官视角
- 核心考察点:能否说出 with 的危害
- 评分标准:
- 差:只会用 with
- 优:能结合作用域和全局变量说明
stage0、stage1、stage2、stage3 分别代表什么含义?
答案
- Stage 0:草案阶段,任何想法都可提交,未被 TC39 正式采纳。
- Stage 1:提案阶段,有负责人和初步方案,值得进一步探讨。
- Stage 2:草案阶段,规范文本基本完成,有实验性实现。
- Stage 3:候选阶段,规范稳定,等待社区和实现者反馈。
- Stage 4:完成阶段,正式纳入 ECMAScript 标准。
答案解析
理解提案流程有助于判断新特性的稳定性和可用性。
面试官视角
- 核心考察点:能否说出各阶段含义
- 评分标准:
- 差:只知 ES6/ES7
- 优:能结合实际举例
装饰器(Decorator)是什么?如何实现?
答案
- 装饰器是一种特殊语法,用于动态修改类、方法、属性等的行为,本质是函数。
- 常用于日志、权限、缓存、AOP 等场景。
- 目前为 ECMAScript 提案,需 Babel 等工具支持。
function timer(target, name, descriptor) { const original = descriptor.value descriptor.value = function (...args) { console.time(name) const result = original.apply(this, args) console.timeEnd(name) return result } return descriptor } class MyClass { @timer myMethod() { // do something } }
答案解析
装饰器让类的扩展更灵活,便于实现横切关注点(如日志、权限)。
面试官视角
- 核心考察点:能否说出装饰器原理和应用场景
- 评分标准:
- 差:只会用,不知原理
- 优:能写简单实现并举例
如何将JavaScript代码解析成抽象语法树(AST)
如何将JavaScript代码解析成抽象语法树
要将JavaScript代码解析成抽象语法树(Abstract Syntax Tree,AST),你可以使用工具或库来实现。以下是几种常用的方法:
- Esprima: Esprima 是一个流行的JavaScript解析器,它可以将JavaScript代码解析成AST。你可以使用它的 JavaScript API 来将代码解析成AST对象。
const esprima = require('esprima')
const code = 'var x = 5;'
const ast = esprima.parseScript(code)
console.log(ast)
- Acorn: Acorn 是另一个广泛使用的JavaScript解析器,它也可以将JavaScript代码解析成AST。你可以使用它的 JavaScript API 来解析代码并获取AST对象。
const acorn = require('acorn')
const code = 'var x = 5;'
const ast = acorn.parse(code, { ecmaVersion: 2020 })
console.log(ast)
- Babel: Babel 是一个功能强大的JavaScript编译器,它可以将代码转换为AST,并提供了丰富的插件系统,用于转换和操作AST。你可以使用 Babel 的 API 来解析代码并获取AST对象。
const babelParser = require('@babel/parser')
const code = 'const x = 5;'
const ast = babelParser.parse(code, { sourceType: 'module' })
console.log(ast)
这些工具和库都可以将JavaScript代码解析成AST对象,从而使你能够对代码进行进一步的分析、转换或处理。你可以根据自己的需求选择其中之一,并根据其文档了解更多关于解析选项和AST节点的信息。
JavaScript代码解析成抽象语法树的原理是什么
JavaScript代码解析成抽象语法树(Abstract Syntax Tree,AST)的过程涉及以下几个主要步骤:
-
词法分析(Lexical Analysis):词法分析器(Lexer)将源代码拆分成词法单元(tokens),比如变量名、关键字、操作符、标点符号等。它根据一组定义好的规则(词法规范)来识别和分类这些词法单元。
-
语法分析(Syntax Analysis):语法分析器(Parser)接收词法分析器生成的词法单元,并根据语法规则构建AST。语法分析器使用上下文无关文法(Context-Free Grammar)来定义语言的语法规则,它通过递归下降、LR(1) 等算法来处理这些规则,以确定输入是否符合语法规则并生成相应的AST。
-
构建AST:在语法分析的过程中,语法分析器根据语法规则构建AST。AST是一个树状结构,其中每个节点表示源代码中的一个语法结构,如表达式、语句、函数等。不同节点类型代表不同的语法结构,它们之间通过父子关系和兄弟关系来表示源代码的层次结构和逻辑关联。
-
后续处理:生成AST后,可以进行进一步的处理和分析。这可能包括语义分析、类型推断、符号解析、代码优化等。这些步骤可以根据具体的需求和工具进行。
总结:将JavaScript代码解析成AST的过程是通过词法分析器将源代码拆分成词法单元,然后语法分析器根据语法规则构建AST。AST提供了对代码结构的抽象表示,便于进一步分析、转换和操作代码。