1. 10 循环体内对每个数组元素赋值为一个函数,函数内使用了循环变量 i, 但由于是 var 定义的变量,不会形成块级作用域,在函数运行时, 访问的变量 i 是外部循环体的变量 i,而这时循环已经结束,变量 i 已经变为 10, 所以输出 10

  2. 报错 在条件判断的结构体内,使用 let 定义了 tmp 变量,由于 let 是将变量定义在块级作用域内, 而且在 let 声明之前是变量的作用死区,不会像 var 一样将变量定义提升到作用域顶部, 所以访问 tmp 变量会报错

  3. Math.min(...arr)

  4. var 会产生变量提升的效果,也就是执行时会在作用域顶部提前声明变量, 然后在赋值语句处才进行赋值,这样就造成可以在 var 声明的变量之前访问该变量。 另外,var 声明的变量作用域范围只有函数作用域和全局作用域 2 种。 let 声明的变量是块级作用域,且不会被提升,在声明语句之前是变量的作用死区, 访问变量会报错。const 声明的变量是常量,除了拥有 let 的特性外, 当使用 const 声明变量为原始值是,变量之后就不能被赋予其他值, 当 const 声明的是对象类型时,该变量中的属性仍然被赋予其他值, 因为 const 声明的变量不能修改的是其对应的内存地址。

  5. 20 setTimeout 会在全局作用域下执行,但是回调函数使用了箭头函数, 箭头函数中的 this 和外层的 this 保持一致,所以 this 仍指向 obj

  6. Symbol 可以创建唯一的变量,不会产生相同的两个 symbol, 由此 Symbol 非常适合作为私有变量的 key,也可以作为唯一的 id, 不受其他模块的代码影响。

  7. 浅拷贝是复制源对象的引用地址,如果源对象是值类型,则拷贝对象是也是值类型,如果源对象是引用类型,则拷贝对象是源对象的引用,如果更改其中的值,源对象也会发生变化。深拷贝是将源对象中的值分别拷贝到新对象中,改变拷贝对象中的值不会引起源对象的改变

  8. JS 是单线程运行的,异步编程是 JS 的编程范式,通过异步的方式,JS 可以同时处理多项任务,当任务完成时,通过回调的方式执行后续步骤。Event Loop 是 JS 的事件轮询机制,当 JS 引擎完成当前任务时,就会去 Event Loop 中查询是否有新的回调任务,如果没有,就进入下一个阶段,如果有任务,就按顺序取出来执行。JS 的宏任务是指 setTimeout、事件回调、IO 回调等产生的任务,微任务是指 promise.then,process.nextTick 等产生的任务,微任务的执行时机是当前宏任务结束时,当微任务队列为空时,再进入下一个宏任务。

function setTimePro(val) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(val);
        }, 10);
    });
}

(async () => {
    const a = await setTimePro('hello')
    const b = await setTimePro('lagou')
    const c = await setTimePro('I ❤ U')
    console.log(a + b + c)
})();
  1. TS 是 JS 的超集,包含了 JS 的所有内容,还包括编译器,可以将 TS 编译成任意 ES 版本的 JS,还包括一整套类型系统,可以进行静态编译,能够在编码阶段就发现代码中的错误,也能更好的方便代码的阅读沟通。

  2. TS 是强类型语言,通过类型约束可以更好的增强代码质量,降低沟通成本,同时也可以代替 Babel 转换代码至低版本的 JS,缺点是需要编写类型定义,多了开发工作量,另外还需要编译生成 JS,开发效率会降低。