用一句话来回答js面试题,直击要领,简单明了。后续在面试过程中吗,可以在这个基础上按照自己的能力来拓展。
数据类型
- js有哪些数据类型:包含有 Undefined、Null、Boolean、Number、String、Object、Symbol、BigInt
- 数据类型区别:基本数据类型,引用数据类型。存储方式不同
- 检测数据类型方式:typeof、instanceof、constructor、Object.prototype.toString.call()
- null和undefined异同:都是基本数据类型,undefined表示未定义、null表示空对象
- instanceof实现原理: 判断构造函数的prototype,是否出现在对象原型链中的位置
- ==与===的区别:双等号若类型不一致先隐式类型转换再判断值一致为真,三等号需要确保类型、值一致则为真。
- Object.is(): 与三等号用法一致,处理了一些特殊情况
- 对象转基础类型规则:优先调用
Symbol.toPrimitive其次是valueOf最后是toString - 数组转数字:空数组为0,含有一个元素且是数字或数字字符串转为该数字,其余为NAN
- 0.1+0.2!==0.3:js采用64位双精度格式来存储数字,存储0.1跟0.2都是无限循环二进制。
js基础
- new 操作符实现原理:创建空对象,将__proto__指向该函数prototype,函数调用this指向obj,如果函数返回引用类型直接返回结果,返回基本类型则返回上述对象。
- map和weakMap区别:weakMap是一种弱引用,key必须是对象。只要引用对象key被清除,其值也会被清除
- js脚本延迟加载方式:defer脚本加载与页面的解析同步执行,页面解析完成后执行、async异步加载不阻塞页面解析,js加载完立马执行,会阻塞页面解析、动态创建dom加载、js放到文档最底部
- 什么是类数组:一个对象,属性是从0开始依次递增的数字,拥有callee和length属性,与数组相似
- 什么是DOM和BOM: dom是指文档对象模型、bom是指浏览器对象模型
- ES6模块和CommonJS模块有什么异同:commonjs是浅拷贝,es6 module是对象引用。都可以对引入的对象进行赋值
原型、原型链
- 什么是原型:函数构造函数拥有一个key为
prototype和实例共享属性跟方法的对象 - 什么是原型链:所有对象都拥有一个key为
__proto__的属性用来指向当前构造函数的原型。一层一层链接起来方式称为原型链 - 继承方式:原型继承、构造函数继承、寄生组合继承、class extends继承
- 原型链的终点:函数原型链终点是
Function.prototype&&Function.prototype===Function.__proto__,对象原型链终点是Object.prototype&&Object.prototype.__proto__=== null。Object是一个函数,所有的.prototype指向的都是一个对象
执行上下文、执行上下文栈
- 什么是执行上下文:代码在运行时用来记录一些信息跟状态的对象
- 执行上下文分类:全局执行上下文、函数执行上下文、
eval函数指向下文 - 什么是执行上下文栈:在代码运行的过程中不断新建跟销毁的执行上下文用栈的数据结构管理起来称之为执行上下文栈。栈底永远是全局执行上下文、栈顶是当前执行上下文。
作用域、作用域链
- 什么是作用域:规定了在代码哪个部分可以访问或查找特定的标识符
- 作用域的分类:全局作用域、函数作用域、块级作用域
- 什么是变量环境:用来存储 var function关键字定义变量的对象
- 什么是词法环境:用来存储let const等这些关键字定义变量的对象
- 什么是作用域链:js查找变量会用当前词法环境或变量环境查找,找不到则通过outer指向的外层作用域查找一级一级往上查。这样的链接称为作用域链
- 作用域链创建时机:js采用静态作用域在函数定义或代码块定义时就会
- 什么是闭包:MDN说闭包是由捆绑起来(封闭的)的函数和函数周围状态(词法环境)的引用组合而成。狭义闭包是函数的变量环境或词法环境被外部执行上下文引用,但该函数的执行上下文已经不再上下文栈中。这种就称之为闭包。
Performance
- FP:首次绘制
- FCP:首次内容绘制,内容包含文本、图片、canvas
- DOMContentLoad(DCL):Dom解析完毕
- load:代表依赖所有资源加载完成
- largest contentful Paint(LCP): 最大内容渲染时间
- First Input Delay(FID):用户第一次与页面交互到浏览器真正能够开始处理事件处理程序以响应该交互的时间。
- Time To Interactive(TTI):页面已经显示有用内容,页面上的可见元素关联的事件响应函数已经完成注册,事件响应函数可以在事件发生后的 50ms 内开始执行。
- First Meaningful Paint(FMP):,首次渲染有意义的内容的时间,“有意义”没有一个标准的定义,FMP的计算方法也很复杂。
- 稳定性指标 CLS: 每一次意外布局变化的最大布局变化得分的度量,布局变化得分越小证明你的页面越稳定
- FPS:流畅性指标
解释以下代码运行机制
var a1 = 1
let a2 = 2
function fn1(){
var b1 = 3
let b2 = 4
console.log(a1,a2,b1,b2)
function fn2(){
let c1 = 5
console.log(a1,a2,b1,b2,c1)
}
}
fn1()
- 将代码丢到浏览器环境运行
- 创建全局执行上下文globalEC
- 全局执行上下文对象包含this指针、variableEnviroment(变量环境)、lexicalEnviroment(词法环境)
- 代码解析给变量提升
- 代码预解析,定义函数fn1的
[[scopes]]属性,添加当前全局词法环境 - 变量环境包含a1、fn1
- 词法环境包含a2即
globalEc = {
this:window, // this 指针
variableEnviroment:{a1:undefined,fn1, outer:null, } // outer 实现作用域链
lexicalEnviroment:{a2,outer:globalEc.variableEnviroment} // 这里会提升,但不可使用 ,使用会报错
}
- 第一行执行变量环境a1赋值为1
- 第二行代码执行a2赋值为2
- 3-11行是函数体已被御解析过
- 12行执行,执行f1开始
- 创建fn1的函数执行上下文包含this指针、variableEnviroment(变量环境)、lexicalEnviroment(词法环境)
- 代码解析变量提升
- 函数fn2被预解析定义,确定函数fn2
[[scopes]]属性,添加当前fn1词法环境 - 第四行执行变量环境b1赋值为3
- 第五行执行词法环境环境b2赋值为4
globalEc = {
this:window, // this 指针
variableEnviroment:{a1:undefined,fn1, outer:null, }
lexicalEnviroment:{a2,outer:globalEc.variableEnviroment}
}
fn1Ec = {
this:window, // this 指针
outer:null, // 来实现作用域链接
variableEnviroment:{b1:undefined,fn2,outer:globalEc.lexicalEnviroment}
lexicalEnviroment:{b2,outer:fn1Ec.variableEnviroment} // 这里会提升,但不可使用 ,使用会报错
}
- 执行第六行输出a1,a2,b1,b2
- a1、a2不在当前词法环境
fn1Ec.lexicalEnviroment - 依次通过
fn1Ec.lexicalEnviroment->fn1Ec.variableEnviroment->globalEc.lexicalEnviroment->globalEc.variableEnviroment的outer按层级查找返回 - 执行第十行
- 执行第十一行
- 代码运行结束
异步、事件环
- 什么是异步:等一个任务完成的同时,去执行其他任务只需要知道结果即可
- js异步:js异步并非真正异步,是通过异步队列来等待浏览器空闲模拟完成异步
- 浏览器同步异步区别:同步按顺序执行,阻塞主线程,可能会导致浏览器卡顿效率比较低;异步是不阻塞主线程页面流畅
- 浏览器异步任务分类:宏任务队列、微任务队列
- 什么是浏览器事件环:每当一个宏任务执行完成后会清空微任务异步队列,周而复始的操作称为浏览器事件环
- Node异步任务分类:宏任务队列、微任务队列、nextTick任务队列
- 什么是Node事件环:按照setTimeout->I/O->poll->setImmidate的阶段顺序,按照每执行一个宏任务,先清空nextTick任务队列,在清空微任务对象,其次再看当前阶段是否有宏任务,如果有继续执行一个宏任务,清空nextTick任务队列,在清空微任务对象。如果没有进入下个阶段看是否有宏任务的顺序,周而复始执行
垃圾回收
- 什么是垃圾:从当前环境出发一直找到根都没有被引用的变量或对象称之为垃圾
- 什么是标记清除法:给内存所有对象添加标记为0,然后从根出发查找使用对象标记为1,清除所有标记为0不被使用的对象
- 什么是引用计数法清除垃圾:按照变量引用加一,赋值覆盖减一的方法,清除引用次数为零的
- 什么是新生代:新产生对象,体积较小1~8M,存活时间较短的对象
- 什么是老生代:活动时间较长。或者是通过新生代垃圾回收存活下的对象
- 新生代回收方式:依次判断每个对象,使用复制到新内存中,复制完成后,清空旧内存区域
- 老生代回收方式:采用标记清除方法来清除
这篇文章可能对初识前端人员不太友好,需要详细更深入的理解每个知识点。如果大家看的过程中有啥需要发的,请积极留言