JavaScript 面试八股文 总结
2022-06-16 16:25:45 1 举报
AI智能生成
点赞的小伙伴都能拿到高薪offer~
作者其他创作
大纲/内容
块级作用域由{}包括,let 和 const 具有块级作用域,var不存在块级作用域
内层变量可能覆盖外层变量
用来计数的循环变量泄漏为全局变量
解决 ES5 的两个问题
1. 块级作用域
var 存在变量提升
let、const 不存在变量提升
2. 变量提升
对于let 是否存在变量提升的思考?
使用 let、const命令声明变量之前,该变量都是不可用的。在语法上称为暂时性死区
3. 暂时性死区
var 声明的变量为全局变量,会将该变量添加为全局对象的属性。let 和 const 不会
浏览器的全局对象为 window, Node 的全局对象为 global
4. 给全局添加属性
var 可重复声明变量
let 和 const 不可重复声明变量
5. 重复声明
在变量声明时,var 和 let 可以不用设置初始值
cosnt 声明变量必须设置初始值
6. 初始值设置
let 声明的变量可以更改指针指向(重新赋值)
简单类型不可修改
复杂类型(对象、数组、函数)可修改
const 声明的变量不允许改变指针的指向
7. 指针指向
let、const、var 的区别
并不是变量的值不能改动,而是变量指向的内存地址不能改动
基本类型 不能改变
引用类型 只能保证指针不改变,内部的值是可以改变的
const 对象的属性可以修改吗
箭头函数是 ES6 提出来的,它没有 prototype,没有自己的 this 指向,更不可以使用 arguments 参数,所以不能 new 一个箭头函数
1. 创建一个全新的对象
2. 将这个新对象的 _proto_ 属性指向构造函数的 prototype 属性
3. 让函数的 this 指向这个对象,执行构造函数的代码(为这个新对象添加属性)
4. 如果函数没有返回其他对象,会自动返回这个新对象
new 操作符的实现步骤
第二、三步,箭头函数是没办法执行的
如果 new 一个箭头函数会怎样
更加简洁
没有自己的 this
箭头函数的 this 绑定定义时所在的作用域
普通函数 this 指向运行时所在的作用域
继承来的 this 指向永远不会改变
call()、apply()、bind() 等方法不能改变箭头函数中 this 的指向
不能作为构造函数使用
没有自己的 arguments
没有 prototype
不能用作 Generator 函数,不能使用 yeild 关键字
箭头函数与普通函数的区别
箭头函数没有自己的 this,它所谓的 this 是捕获其所在上下文的 this 值,作为自己的 this 值
由于没有 this 值,所以是不会被 new 调用的,这个所谓的 this 也不会被改变
箭头函数的 this 指向哪里
用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中
如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性
对象扩展运算符
调用-Iterator-接口的场合
扩展运算符是调用 iterator 的接口,实际上任何部署了 Iterator 接口的数据结构都可以通过扩展运算符转为数组
每次只能展开一层数组
将数组转化为参数序列
复制数组
合并数组
扩展运算符与解构赋值结合,用于生成数组。这里的扩展运算符只能放在参数的最后一位,否则报错
将字符串转为真正的数组
使用 Math 函数获取数组中特定的值
使用场景
数组扩展运算符
扩展运算符的作用及其使用场景
Proxy 是 ES6 新增的功能,它可以用来自定义对象中的操作
无需一层层递归为每个属性添加代理,一次性即可完成这些操作,性能更好
原本的实现有一些数据更新不能监听到,但是 Proxy 可以完美监听任何方式的数据改变
优点
浏览器的兼容性不好
缺点
在 Vue 3.0 中通过 Proxy 来替换原本的 Object.defineProperty 来实现数据响应式
Proxy 可以实现什么功能
解构是 ES6 提供的一种新的提取数据的模式,这种模式能够从对象或数组里有针对性地拿到想要的数据
通过设置占空位,进行精准提取
以元素的位置为匹配条件来提取想要的数据
数组的解构
以属性的名称为匹配条件来提取想要的数据
对象的解构
对对象与数组的解构的理解
const { classes: { stu: { name } } } = schoolconsole.log(name) // River
获取里面的 name 变量,可以通过 冒号 + {目标属性名} 这种形式
如何提取高度嵌套的对象里的指定属性
剩余参数语法允许我们将一个不定数量的参数表示为一个数组
如果函数的最后一个命名参数以 ... 为前缀,则它将成为一个由剩余参数组成的真数组
使用
经常用于获取函数的多余参数,或者梳理函数参数个数不确定的情况
场景
对 rest 参数的理解
在模板字符串中,空格、缩进、换行都会被保留
模板字符串完全支持“运算”式的表达式,可以在 ${} 里完成一些计算
模板语法允许以 ${} 的方式嵌入变量
indexOf > -1
过去
判断字符串与子串的包含关系
includes
判断字符串是否以某个/某串字符开头
startsWith
判断字符串是否以某个/某串字符结尾
endsWith
现在
返回布尔值
存在性判定:判断一个字符或字符串是否存在于某字符串中
const sourceCode = 'repeat for 3 times;'const repeated = sourceCode.repeat(3)console.log(repeated) // repeat for 3 times;repeat for 3 times;repeat for 3 times;
自动重复:可以使用 repeat 方法来使同一个字符串输出多次(被连续复制多次)
字符串处理方法
ES6 中模板语法与字符串处理
ES6
原型链涉及到的东西挺多的,我举个例子说明一下吧
举例说明什么是原型
举例说明什么是原型链
怎么做
解决了什么问题
解决缺点的方法
对原型、原型链的理解
修改
重写
原型的修改、重写
constructor
终点:null
打印:Object.prototype.__proto__
原型链的终点是什么?如何打印出原型链的终点?
hasOwnProperty
getOwnProperty
如何获得对象非原型链上的属性
原型
异步编程的实现方式
setTimeout、Promise、Async/Await 的区别
对 Promise 的理解
Promise 的基本用法
Promise 解决了什么问题
Promise.all 和 Promise.race 的区别和使用场景
对 async/await 的理解
await 到底在等啥
async/await 的优势
async/await 对 Promise 的优势
async/await 如何捕获异常
并发与并行的区别
什么是回调函数?回调函数有什么缺点?如何解决回调地狱问题?
setTimeout、setInterval、requestAnimationFrame 各有什么特点
异步编程
对闭包的理解
对作用域、作用域链的理解
对执行上下文的理解
执行上下文/作用域链/闭包
对 this 对象的理解
call() 和 apply() 的区别
实现 call、apply 及 bind 函数
this/call/apply/bind
对象创建的方式有哪些
对象继承的方式有哪些
面向对象
浏览器的垃圾回收机制
哪些情况会导致内存泄漏
垃圾回收与内存泄漏
创建后独一无二且不可变的数据类型
主要为了解决可能出现的全局变量冲突的问题
Symbol
是一种数字类型的数据,可以表示任意精度格式的整数
可以安全地存储和操作大整数,即使这个数已经超出了 Number 能够表示的安全整数范围
BigInt
ES6 新增数据类型
直接存储在栈(stack)中的简单数据段,占据空间小、大小固定、频繁使用,所以放入栈中存储
存储在堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中,会影响程序运行的性能。
在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体
引用数据类型Object
分类
栈中数据先进后出
堆是一个优先队列,按照优先级来进行排序,优先级可以按照大小来规定
数据结构
栈区内存由编译器自动分配释放,存放函数的参数值、局部变量的值等
堆区内存一般由开发者分配释放,若开发者不释放,程序结束时可能由垃圾回收机制回收
操作系统
堆和栈的概念
区别:存储位置不同
JavaScript 有哪些数据类型及它们的区别
通常用来判断基本数据类型,历史遗留问题:typeof null === 'object'
判断引用数据类型会返回'object',特殊情况:typeof function(){} === 'function'
1. typeof返回 string
只能正确判断引用数据类型,不能判断基本数据类型
内部运行机制:判断在其原型链中能否找到该类型的原型
可以用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性
也可能判断不准确,比如一个数组,可以被判断为 Object,想要准确判断可以采用——
2. instanceof返回true/false
判断数据类型
obj.constructor // 返回的是构造函数
对象实例通过 constructor 对象访问它的构造函数
作用
function Fn(){}Fn.prototype = new Array()var f = new Fn()console.log(f.constructor === Fn) // falseconsole.log(f.constructor === Array) // true
如果创建一个对象来改变它的原型,就不能用来判断数据类型了
3. constructor
使用 Object 对象的原型方法 toString() 来判断
toString 是 Object 的原型方法,而Array、Function等作为Object的实例,都重写了toString方法。
let Foo = new Object()Foo.toString() // '[object Object]'
let Bar = function(){}Bar.toString() // 'function(){}'
obj.toString() 和 Object.prototype.toString.call(obj)
4. Object.prototype.toString.call()返回 string
数据类型检测的方式有哪些
obj.__proto__ === Array.prototype
Array.prototype.isPrototypeOf(obj)
ES6 Array.isArray(obj)
obj instanceof Array
判断数组的方式有哪些
相同:都是基本数据类型,分别都只有一个值,undefined 和 null
表示“缺少值”,就是此处应该有一个值,但是还没有定义
变量被声明了,但没有赋值时,就等于 undefined
对象没有赋值的属性,该属性的值为 undefined
调用函数时,应该提供的参数没有提供,该参数等于 undefined
函数没有返回值时,默认返回 undefined
undefined 在 JavaScript 中不是一个保留字,undefined 可以作为变量名使用,为了安全起见,可以通过 void 0 这种方式获得 undefined值
undefined:未定义
典型用法
表示“空对象”,即该处不应该有值
作为函数的参数,表示该函数的参数不是对象
作为对象原型链的终点
null:空对象
ES规范就这么规定的
== 自动类型转换,===不会进行类型转换
undefined == null // true,undefined === null // false
null 和 undefined 的区别
结果是 'object'
在最初的 JavaScript 中,所有值都存储在 32 位的单元中,每个单元包含一个(1-3bits)的类型标签以及当前要存储值的真实数据
000:object
1:int
010:double
100:string
110:boolean
类型标签存储在每个单元的低位中,共五种数据类型
undefined 的值是 (超出整数范围的数字)
所以 null 的类型标签也是 000,和 Object 的类型标签一样,所以会被判定为 Object
null 的值是机器码 NULL 指针(null 指针的值全是 0)
有两种特殊数据类型
typeof null 的结果是什么,为什么
instanceof 运算符用于判断构造函数的 prototype 属性是否出现在对象的原型链中的任何位置
instanceof 操作符的实现原理及实现
二进制计算
无限循环
双精度浮点数
为什么
toFixed()
Number.EPSILON
如何相等
为什么 0.1 + 0.2 !== 0.3,如何让其相等
因为 undefined 是一个标识符,所以可以被当做变量来使用和赋值,从而影响 undefined 的正常判断
运算符 void 对给定的表达式进行求值,然后返回 undefined。因此可以用 void 0 来获得undefined。
如何获取安全的 undefined 值
typeof NaN // 'number'
NaN(not a number):不是一个数字
NaN 是一个警戒值(有特殊用途的常规值),用于指出数字类型中的错误情况,即“执行数学运算没有成功,这是失败后返回的结果”
NaN !== NaN // true
NaN 是一个特殊值,它和自身不相等,是唯一一个非自反的值
typeof NaN 的结果是什么
转换为数值=>任何不能被转换为数值的值都返回 true因此非数字值传入也会返回 true
isNaN
是否为数字 => 是数字再判断是否为 NaN不会进行数据类型的转换,更准确
Number.isNaN
isNaN 和 Number.isNaN 函数的区别
1. 首先会判断两者类型是否相同,相同就比较两者的大小
2. 类型不同,就进行类型转换
3. 先判断是否在对比 null 和 undefined,是的话就返回 true
4. 判断两者的类型是否为 string 和 number,是的话就将字符串转为 number
5. 判断其中一方是否为 boolean,是的话就把 boolean 转为 number
6. 判断其中一方是否为 object,且另一方为 string、number 或者 symbol,是的话就把 object 转为原始类型再进行判断
== 操作符的强制类型转换规则
null => \"null\
Boolean: true => \"true\
Number:直接转换,极小和极大的数字会使用指数形式
Symbol:直接转换,只允许显式强制类型转换,使用隐式强制类型转换会产生错误
调用toString( Object.prototype.toString() ) 返回内部属性 [[Class]] 的值,如'[object Object]'
new Date() => Fri Apr 22 2022 00:55:33 GMT+0800 (中国标准时间)
除非自定义 toString() 方法,字符串化时就会调用该方法并使用其返回值
普通对象:
其他值到字符串的转换规则
Undefined 类型:NaN
Null 类型:0
包含非数字值 NaN
空字符串 0
String
Symbol:不能转换为数字,会报错
首先会被转换为相应的基本类型值,如果返回的是非数字的基本类型值,则再遵循以上规则将其强制转换为数字
对象:
其他值到数字值的转换规则
undefined
null
false
+0、-0 和 NaN
\"\"
假值
假值的布尔强制类型转换结果为 false。逻辑上说,除了假值列表外的都应该是真值。
其他值到布尔类型值的转换规则
|| 和 && 首先会对第一个操作数执行条件判断,如果其不是布尔值就先强制转换为布尔类型再执行条件判断
||:如果这个条件判断为 true,则返回第一个操作数的值,如果为 false,则返回第二个操作数的值
&&:如果这个条件判断为 true,则返回第二个操作数的值,如果为 false,则返回第一个操作数的值
|| 和 && 返回它们其中一个操作数的值,而非条件判断的结果
|| 和 && 操作符的返回值
强制类型转换后再进行比较
==
不会强制类型转换
===
一般情况和 === 判断相同
-0 和 +0 不再相等
两个 NaN 相等
特殊情况,例如:
Object.is
Object.is() 与比较操作符 “===”、\"==\"的区别
在 JavaScript 中,基本类型是没有属性和方法的,为了便于操作基本类型的值,在调用基本类型的属性或方法时 JavaScript 会在后台隐式地将基本类型的值转换为对象
如:const a = \"abc\"a.length //3a.toUpperCase() // \"ABC\"
在访问 'abc'.length 时,JavaScript 将 'abc' 在后台转换成 String('abc'),然后再访问其 length 属性
var a = 'abc'Object(a) // String {\"abc\"}
JavaScript 也可以使用 Object 函数显式地将基本类型转换为包装类型
var a = 'abc'var b = Object(a)var c = b.valueOf() // 'abc'
也可以使用 valueOf 方法将包装类型倒转成基本类型
什么都不会打印,虽然包裹的基本类型是 false,但是 false 被包裹成包装类型后就成了对象,所以其非值为 false,所以循环体中的内容不会运行
var a = new Boolean(false)if(!a) { console.log(\"oops\")} // never runs
什么是 JavaScript 中的包装类型
obj 是基本类型,直接返回值本身
obj 是对象
obj:需要转换的对象
1. 调用 obj 的 toString,如果为原始值,则返回,否则下一步
2. 调用 obj 的 valueOf 方法,后续同上
3. 抛出 TypeError 异常
Date 对象,type 默认 string
string
1. 调用 obj 的valueOf 方法,如果为原始值,则返回,否则下一步
2. 调用 obj 的 toString 方法,后续同上
其他情况,type 默认为 number
number
type:期望的结果类型
字符串连接符
其他情况,变量都转换为数字
算数运算符
+
变量都转换为数字
- * /
都尽量转成 number
若都是字符串,则比较字母顺序
其他情况,转换成数字再比较
特殊情况1:unll 和 undefined 进行 == 比较时不会转换,总是返回 true
[] == [] // false两个数组的地址指向不同
特殊情况2:若都是引用数据类型,会进行地址比较
< >
基本类型的值在不同操作符的情况下的隐式转换规则
+ 比较特殊
步骤1:ToPrimitive 转换为基本类型
步骤2:在不同操作符情况下的隐式转换
对象
JavaScript 中如何进行隐式类型的转换
+ 的其中一个操作数是字符串
如果其中一个操作数是对象,首先对其调用 ToPrimitive 抽象操作,该抽象操作再调用 [[DefaultValue]],以数字作为上下文
如果不能转换为字符串,则会将其转换为数字类型来进行计算
或通过右边步骤,最终的得到字符串
+ 操作符什么时候用于字符串的拼接
JavaScript 中的 Number.MAX_SAFE_INTEGER——最大安全数字,9007199254740991
在这个数范围内不会出现精度丢失(小数除外)
超出这个范围会出现计算不准确的情况,因此官方提出 BigInt 来解决此问题
为什么会有 BigInt 提案
都是浅拷贝
接受第一个参数作为目标对象,将所有可枚举的属性值从一个或多个源对象复制到目标对象,拷贝的是属性值。
可以触发 ES6 setter
Object.assign()
将数组或对象中的每一个值都拷贝到一个新的数组或对象中,不复制继承的属性或类的属性。(原型的属性)
扩展运算符
区别
object.assign 和 扩展运算法是深拷贝还是浅拷贝,两者区别
数据类型
步骤
代码
具体实现
new 操作符的实现原理
【了解】map 和 Object 的区别
键值对的集合
本质
普通 Object 的键值对中的键只能是字符串,而 ES6 提供的 Map 键值对中的键可以是任意类型,是一种更加完善的 Hash 结构
和 Object 的区别
如果 Map 的键是一个原始数据类型,只要两个键严格相同,就视为同一个键
键
const map = [ [\"name\
实际上 Map 是一个数组,它的每一个数据也都是一个数组
什么是 Map
size
get(key)
has(key)
delete(key)
clear()
操作方法(6种)
keys()
values()
entries()
遍历器生成函数(3个)
三个参数
forEach()
遍历方法(1个)
遍历
Map
键值对的集合,其中键是弱引用的
必须是对象,原始数据类型不能作为 key 值(null除外)
和 Map 的区别
什么是 WeakMap
注:clear() 已弃用,可以通过创建一个空的 WeakMap 并替换原对象来实现清除
操作方法(4种)
键名所引用的对象都是弱引用,即垃圾回收机制不将该引用考虑在内,只要所引用对象的其他引用都被清除,垃圾回收机制就会自动释放该对象所占用的内存
WeakMap
Map 可以是任意类型
WeakMap 只能接受对象(null 除外)
1. 键的类型
WeakMap 的键是弱引用,键所指向的对象可以被垃圾回收
2. 键的引用
Map 可以被遍历
WeakMap 不能被遍历
3. 遍历
Map 和 WeakMap 的区别
【了解】map 和 weakMap 的区别
区别于 global object (全局对象)
global objects 全局的对象(标准内置对象)
js 中的内置对象主要指的是 在程序执行前存在全局作用域里的、由 js 定义的一些全局值属性、函数和用来实例化其他对象的构造函数。一般经常用到的如全局变量 NaN、undefined,全局函数如 ParseInt()、parseFloat(),用来实例化对象的构造函数如 Date、Object等,还有提供数学计算的弹体内置对象如 Math。
回答
Infinity
NaN
这些全局属性返回一个简单值,这些值没有自己的属性和方法
值属性
eval()
parseFloat()
parseInt()
全局函数可以直接调用,不需要在调用时指定所属对象,执行结束后会将结果直接返回给调用者
函数属性
Object
Function
Boolean
Error
基本对象是定义或使用其他对象的基础。包括一般对象、函数对象和错误对象
基本对象
Number
Math
Date
用来表示数字、日期和执行数学计算的对象
数字和日期对象
RegExp
用来表示和操作字符串的对象
字符串
Array
这些对象表示按照索引值来排序的数据集合,包括数组和类型数组,以及类数组结构的对象
可索引的集合对象
Set
WeakSet
这些集合对象在存储数据时会使用到键,支持按照插入顺序来迭代元素
使用键的集合对象
SIMD
SIMD 矢量集合中的数据会被组织为一个数据序列
矢量集合
JSON
这些对象用来表示和操作结构化的缓冲区数据,或使用 JSON 编码的数据
结构化数据
Promise
Generator
控制抽象对象
Reflect
Proxy
反射
Intl
Intl.Collator
为了支持多语言处理而加入 ECMAScript 对象
国际化
arguments
其他
JavaScript 中有哪些内置对象
var regx = /#[0-9a-fA-F]{6}[0-9a-fA-F]{3})/g
匹配16进制颜色值
var regx = /^[0-9]{4}-(0[1-9]1[0-2])-(0[1-9]|[12][0-9]|3[01])$/
匹配日期,如 yyyy-mm-dd 格式
匹配 qq 号
var regx = /^1[34578]\\d{9}$/g
手机号码
用户名
常用的正则表达式有哪些
JavaScript Object Notation --- JS 对象标记语言
注意!JSON 是一门语言,但不是编程语言,而是标记语言,与此类似的还有 HTML、XML、MarkDown,用来展示数据
解析 JSON 字符串
JSON.parse()
将一个 JavaScript 对象或值 转换为 JSON 字符串
JSON.stringify()
方法
对 JSON 的理解
延迟加载就是等页面加载完成之后再加载 JavaScript 文件
延迟加载有利于提高页面加载速度
在 script 标签中设置 defer 属性,HTML 解析时,并行加载 JS,HTML 解析完再执行 JS
文档解析完成后再执行脚本文件,使页面的渲染不被阻塞
多个设置了 defer 属性的脚本,按照脚本出现的顺序加载和执行
1. defer 属性
在 script 标签中设置 async 属性,HTML 解析时,并行下载 JS,执行 JS,然后再解析 HTML
脚本加载完成后立即执行,如果HTML没有解析完成同样会阻塞
多个 async 属性的脚本执行顺序是不可预测的,一般不会按照代码的顺序依次执行
2. async 属性
可以对文档的加载事件进行监听,当文档加载完成后再动态的创建 script 标签来引入 js 脚本
3. 动态创建 DOM 方式
设置一个定时器来延迟加载 js 脚本文件
4. 使用 setTimeout
将 JS 脚本放在文档底部,使 JS 脚本尽可能在最后来加载执行
5. 让 JS 最后加载
方式
更优,可以并行下载 js。相较起来,defer 优于 async
JavaScript 脚本延迟加载的方式有哪些
一个拥有 length 属性和若干索引属性的对象就可以被称为类数组对象
定义
类数组与数组相似,但是不能调用数组的方法
getElementsTagName
getElementsByClassName
getElementsByName
等
DOM 方法的返回结果
例如
1. 通过 call 调用数组的 slice 方法来实现转换
2. 通过 call 调用数组的 splice 方法来实现转换
3. 通过 apply 调用数组的 concat 方法来实现转换
4. 通过 Array.from 来实现转换
类数组转换为数组的方法
JavaScript 类数组对象的定义
返回字符串
toString()
??????????
toLoaclString()
可以指定转换为字符串时的 分隔符
join()
数组和字符串的转换方法
返回该元素的值
删除数组的最后一个元素
pop()
push()
数组尾部操作方法
数组有哪些原生方法
Unicode、UTF-8、UTF-16、UTF-32 的区别
JavaScript基础
考察频次高
考察频次较高
考察频次一般
考察频次较少
Tips:
JavaScript 八股文
收藏
收藏
0 条评论
回复 删除
下一页