一、JavaScript基础

240 阅读9分钟

前端工程师吃饭的家伙,深度、广度一样都不能差。
书籍推荐
《你不知道的JavaScript》 上中下
《JavaScript语言精粹》
《深入理解ES6》
《JavaScript设计模式与开发实践》
《高性能JavaScript》
《JavaScript高级程序设计》

变量和类型

  • 1.JavaScript规定了几种语言类型 六种基本类型: Number、String、Boolean、Null、Undefined、Symbol
    一种引用类型: Object

  • 2.JavaScript对象的底层数据结构是什么

V8里面所有的数据类型的根父类都是Object(引擎层的 Object 类),Object派生HeapObject,提供存储基本功能,往下的JSReceiver用于原型查找,再往下的JSObject就是JS里面的Object,Array/Function/Date等继承于JSObject。

  • 3.JavaScript中的变量在内存中的具体存储形式

JavaScript基本类型数据都是直接按值存储在栈(Stack)中(UndefinedNull、不是new出来的booleanNumberString),每种类型的数据占用的内存空间的大小是确定的,并由系统自动分配和自动释放。这样带来的好处就是,内存可以及时得到回收,相对于堆来说 ,更加容易管理内存空间。

JavaScript引用类型数据被存储于堆(Heap)中 (如对象、数组、函数等,它们是通过拷贝new出来的)。其实,说存储于堆中,也不太准确,因为,引用类型的数据的地址指针是存储于栈中,当我们想要访问引用类型的值的时候,需要先从栈中获得对象的地址指针,然后,在通过地址指针找到堆中的所需要的数据。

  • 4.出现小数精度丢失的原因,JavaScript避免精度丢失的方法

由于Js的所有数字类型都是双精度浮点型(64位二进制)采用 IEEE754 标准,浮点数的运算精度丢失问题就是因为,浮点数转化为该标准的二进制的过程中出现的丢失。
解决办法:
思路1:将小数转化为整数进行运算(整数不会精度丢失)
思路2:限制精度,只保留小数部分位数,减小精度出现的误差问题
思路3:使用第三方封装类库:math

  • 5.类型检测方法

Object.prototype.toString.call()

执行机制

  • 1.JavaScript如何实现异步编程,什么是Eventloop?

JS 异步编程进化史:callback -> promise -> generator -> async + await
还能用事件监听、发布订阅等实现异步编程
采用任务队列与事件循环实现异步

主要参考:
彻底理解js是单线程的
JavaScript 运行机制详解:再谈Event Loop
图解浏览器和 Node.js 环境下的 Event Loop
图解浏览器及nodeJS中的EventLoop事件循环机制
JavaScript的宏任务与微任务

eventloop
它是一个在 JavaScript 引擎等待任务,执行任务和进入休眠状态等待更多任务这几个状态之间转换的无限循环。虽然JS是单线程的,但浏览器却是多线程,而eventLoop就是沟通JS引擎线程和浏览器线程的桥梁,也是浏览器实现异步非阻塞模型的关键。

几个重要概念:
执行栈
当一系列方法被依次调用的时候,因为js是单线程的,同一时间只能执行一个方法,于是这些方法被排队在一个单独的地方,即执行栈。所有同步任务都在主线程上执行,形成一个执行栈。
任务队列
js引擎遇到一个异步事件后并不会一直等待其返回结果,而是会将这个事件挂起,继续执行执行栈中的其他任务。当一个异步事件返回结果后,js会将这个事件加入与当前执行栈不同的另一个队列,我们称之为任务队列。IO设备完成一项任务,就在"任务队列"中添加一个事件,表示相关的异步任务可以进入"执行栈"了。主线程读取"任务队列",就是读取里面有哪些事件。
宏任务

  1. setTimeout
  2. setInterval
  3. setImmediate (Node独有)
  4. requestAnimationFrame (浏览器独有)
  5. I/O
  6. UI rendering (浏览器独有) 宏任务便是 JavaScript 与宿主环境(如:浏览器)产生的回调,需要宿主环境配合处理并且会被放入回调队列的任务都是宏任务

微任务

  1. process.nextTick (Node独有)
  2. Promise
  3. Object.observe
  4. MutationObserver 一个事件循环中,在执行队列里的任务执行完毕以后,会有一个单独的步骤,叫 Perform a microtask checkpoint,即执行微任务检查点。这个操作是检查作业队列中是否有微任务,如果有,便将作业队也会当作执行队列来继续执行,完毕后将执行队列置空。
  • 在当前宏任务任务后,下一个宏任务之前,在渲染之前;
  • 所以它的响应速度相比 setTimeout(因为 setTimeout 是宏任务)会更快,因为无需等渲染;
  • 在某一个宏任务执行完后,就会将在它执行期间产生的所有微任务都执行完毕(在渲染前)
  • 2.Node与浏览器EventLoop的差异

node
外部输入数据-->轮询阶段(poll)-->检查阶段(check)-->关闭事件回调阶段(close callback)-->定时器检测阶段(timer)-->I/O事件回调阶段(I/O callbacks)-->闲置阶段(idle, prepare)-->轮询阶段...

浏览器
(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步。
浏览器中的各种 Web API 为异步的代码提供了一个单独的运行空间,当异步的代码运行完毕以后,会将代码中的回调送入到 Task Queue(任务队列) 中去,等到调用栈空时,再将队列中的回调函数压入调用栈中执行,等到栈空以及任务队列也为空时,调用栈仍然会不断检测任务队列中是否有代码需要执行,这一过程就是完整的 Event Loop

  1. 事件循环是 浏览器 和 Node 执行JS代码的核心机制,但浏览器 和 NodeJS事件循环的实现机制有些不同。
  2. 浏览器事件循环有一个宏队列,一个微队列,且微队列在执行过程中一个接一个执行一直到队列为空,宏队列只取队首的一个任务放入执行栈执行,执行过后接着执行微队列,并构成循环。
  3. NodeJS事件循环有四个宏队列,两个微队列,微队列执行方式和浏览器的类似,先执行Next Tick Queue所有任务,再执行Other Microtask Queue所有任务。 但宏队列执行时会依次执行队列中的每个任务直至队为空才开始再次执行微队列任务。
  4. 宏队列(MacroTask)包括: setTimeout、setInterval、 setImmediate(Node)、requestAnimation(浏览器)、IO、UI rendering
  5. 微队列(Microtask)包括: process.nextTick(Node)、Promise、Object.observe、MutationObserver
  • 3.如何在保证页面运行流畅的情况下处理海量数据

前端计算十万条数据量
运行者 Worker 接口是Web Workers API的一部分,代表一个后台任务,它容易被创建并向创建者发回消息。创建一个运行者只要简单的调用Worker()构造函数,指定一个脚本,在工作线程中执行。

前端渲染十万条数据
分页,虚拟列表,渲染三屏幕;时间分片

  • 标记清除法
  • 引用计数法
  • 复制算法 现代浏览器基本上是3种方法的组合处理GC问题,V8 的 GC 算法统称为分代垃圾回收算法,通过记录对象的引用次数,将超过一定引用次数的对象划分为老年对象,剩下的称之为新生代对象,然后分别对他们采用不同到的垃圾回收算法。
    那么对于这种新生代对象来说,回收就会变得很频繁,如果使用 GC 标记清除算法,那么就意味着每次清除过程需要处理很多的对象,会浪费大量的的时间。于是如果对新生代对象采用 GC 复制算法的只需要将活动对象复制出来,然后将整个 From 清空即可,无需再去遍历需要清除的对象,达到优化的目的。而针对老年对象则不同,它们都有多个引用,也就意味着它们成为非活动对象的概率较小,也就可以理解为老年对象不会轻易变成垃圾。再进一步也就是老对象产生的垃圾很少,如果采用复制算法的话得不偿失,大量的老年对象被复制来复制去也会增加负担,所以针对老年对象采用的是标记清除法,需要清除的老年对象只是少数,这样标记清除算法会更有优势。

原型和原型链

  • 1.理解原型设计模式以及JavaScript中的原型规则

  • 2.instanceof的底层实现原理,手动实现一个instanceof

  • 3.可以描述new一个对象的详细过程,手动实现一个new操作符

  • 4.理解es6 class构造以及继承的底层实现原理

作用域和闭包

  • 1.理解词法作用域和动态作用域

  • 2.理解JavaScript的执行上下文栈,可以应用堆栈信息快速定位问题

  • 3.闭包的实现原理和作用,可以列举几个开发中闭包的实际应用

  • 4.理解堆栈溢出和内存泄漏的原理,如何防止

语法和API

  • 1.熟练应用mapreducefilter 等高阶函数解决问题

  • 2.setInterval需要注意的点,使用settimeout实现setInterval

  • 3.JavaScript提供的正则表达式API、可以使用正则表达式(邮箱校验、URL解析、去重等)解决常见问题

  • 4.JavaScript异常处理的方式,统一的异常处理方案

问题收录主要参考
一名【合格】前端工程师的自检清单