JavaScript ES6 面试题
1. let、var、const
let 命令
ES6 中新增的用于声明变量的关键字。它的用法类似于 var,但是所声明的变量,只在 let 命令所在的代码块内有效。
特性:
变量不能重复声明
块儿级作用域
不存在变量提升
不影响作用域链
const 命令
const 声明一个只读的常量。一旦声明,常量的值就不能改变。
特性:
一定要赋初始值
一般常量使用大写(潜规则)
常量的值不能修改
块儿级作用域
对于数组和对象的元素修改,不算做对常量的修改,不会报错
var、let、const 的区别?
(1)变量提升:var 存在变量提升。let 和 const 没有。
(2)块级作用域:var 没有块级作用域。let 和 const 有。
(3)重复声明:var 可以重复声明。let 和 const 不可以。
(4)修改声明变量:var 和 let 可以,const 是常量,不能修改引用的指针,可以修改属性值。
const 对象的属性可以修改吗?
2. 箭头函数
箭头函数的概念
箭头函数是 ES6 中的一种新的函数声明方式,使用箭头(=>)取代了传统的 function 关键字。箭头函数具有更简洁的语法,并且自动绑定了上下文,解决了回调函数中 this 指向问题。
特性:
this 是静态的。this 始终指向函数声明时所在作用域下的 this 的值
不能作为构造实例化对象
不能使用 arguments 变量
箭头函数的简写
//1)省略小括号,当形参有且只有一个的时候
let add = n => {
return n + n;
}
console.log(add(9));
//2) 省略花括号,当代码体只有一条语句的时候,此时 return 必须省略
let pow = (n) => n * n;
console.log(pow(8));
箭头函数和普通函数的区别?
(1)语法简洁性:箭头函数使用箭头(=>)来定义,省略了 function 关键字和大括号,使得语法更加简洁。例如,(x) => x * 2 是一个简单的箭头函数表达式,相当于普通函数 function(x) { return x * 2; }。
(2)this 的绑定:箭头函数没有自己的 this 绑定,它会继承外层作用域的 this 值。而普通函数的 this 值是根据调用时的上下文决定的。这意味着箭头函数中的 this 指向的是在定义时所在的上下文环境对象的 this,如果没有上下文环境对象,则指向最外层对象 window。
(3)构造函数的使用:箭头函数不能用作构造函数,不能使用 new 关键字实例化对象。普通函数则可以被用作构造函数创建对象实例。
(4)arguments 对象:箭头函数没有自己的 arguments 对象,它会继承外层作用域的 arguments 对象。而普通函数则会创建自己的 arguments 对象。
(5)原型属性:箭头函数没有原型属性(prototype)。这意味着它们不能通过原型链来共享属性和方法。
(6)调用方式:箭头函数不能通过 call()、apply()或 bind()方法来改变 this 的指向。这些方法在普通函数中可以用来改变函数执行时的上下文。
(7)匿名性:箭头函数总是匿名的,它们没有自己的名称。而普通函数可以有具体的名称。
如果 new 一个箭头函数的会怎么样?
箭头函数的 this 指向哪⾥?
3. 解构赋值
解构赋值的概念
解构赋值是一种从数组或对象中提取值并赋值给变量的语法。在 ES6 中,可以使用解构赋值语法快速获取数组或对象中的元素,简化了代码编写和数据交换。
用途:
交换变量的值
从函数返回多个值
函数参数的定义
提取 JSON 数据
函数参数的默认值
遍历 Map 结构
输入模块的指定方法
对象与数组的解构的理解?
如何提取高度嵌套的对象里的指定属性?
4. 函数的默认参数
函数的默认参数概念
ES6 引入了函数的默认参数,允许在函数定义时为参数提供默认值。如果调用时未传递参数,将使用默认值。这样可以简化函数的使用,并且可以传递部分参数,而不是全部参数。
对 rest 参数的理解?
5. 扩展运算符(…)
扩展运算符的概念
扩展运算符可以将数组或对象展开,提取出其中的元素。在函数调用或数组和对象字面量中,使用…语法可以将数组或对象展开成独立的元素,或将多个元素合并成数组或对象。
扩展运算符的作用及使用场景?
6. 模板字符串(“)
模板字符串的概念
模板字符串是一种更方便的字符串拼接方式,使用反引号(`)定义字符串,并可以在其中插入变量和表达式,提高了代码的可读性和可维护性。
ES6 中模板语法与字符串处理
7. class 类
Class 的概念
ES6 引入了类(class)的语法糖,使得面向对象编程更加简洁和易用。类可以通过 extends 关键字实现继承,使用 super 关键字调用父类的方法。此外,ES6 还引入了模块化的概念,通过 import 和 export 关键字可以方便地导入和导出模块。
知识点:
class 声明类
constructor 定义构造函数初始化
extends 继承父类
super 调用父级构造方法
static 定义静态方法和属性
父类方法可以重写
如何判断一个对象是否属于某个类?
8. Promise
Promise 的概念
Promise 是 ES6 引入的异步编程的新解决方案。回调函数和异步编程是 js 特点之一,但是 js 中传统的回调函数编写太麻烦,如果嵌套的回调函数层级过多会导致回调地狱,代码很难看,因此 promise 在 es6 被引入用来解决这个问题。语法上 Promise 是一个构造函数用来封装异步操作并可以获取其成功或失败的结果。
Promise 作用
主要用于处理 JS 中异步操作,解决回调地狱的问题。
Promise 对象可以处于以下三种状态之一:
(1)Pending(进行中):初始状态,表示异步操作正在进行中,尚未完成。
(2)Fulfilled(已完成):表示异步操作已经成功完成,可以获取到异步操作的结果。
(3)Rejected(已失败):表示异步操作失败,无法获得异步操作的结果。
Promise 流程:promise 从 pending 状态开始,如果成功则转移到 fulfilled 状态并执行 resolve 回调函数;如果失败则转到 rejected 状态并执行 reject 回调函数。
Promise 的特点
Promise 对象一旦状态改变,就会凝固,无法再次改变。
Promise 支持链式调用,可以通过 then() 方法指定异步操作成功和失败时的回调函数。
Promise 基本用法
promise 方法
(1)then 方法:接收两个参数,第一个是当 promise 对象成功时调用的 resolve 函数,第二个是当 promise 对象失败时调用的 reject 函数。
(2)catch 方法:用于捕获 Promise 发生错误或者失败时的回调函数,
(3)finall 方法:回调函数不接受任何参数,无论 promise 的状态是成功还是失败都会执行。
(4)all 方法:接受一个包含多个 Promise 的可迭代对象(如数组),返回一个新的 Promise。这个新的 Promise 在传入的所有 Promise 都成功完成时才会被成功解决,如果有一个 Promise 失败,则整个 Promise.all 将被拒绝,all 的方法里的 promise 并不是一个个的顺序执行的,而是同时开始、并行执行的。
(4)race 方法:接受一个包含多个 Promise 的可迭代对象,返回一个新的 Promise。这个新的 Promise 在传入的 Promise 中有一个率先解决(无论是成功还是失败),则它就会解决或拒绝。
9. async、await
async、await 的作用
通过同步的方式操作异步代码,解决 Promise 层层嵌套的问题。
原理:遵循 Generator 函数和 Promise 实现的。
(1)async:async 关键字用于声明一个函数是异步的。异步函数会返回一个 Promise 对象,可以使用 await 关键字在异步函数内部等待其他 Promise 对象的解决或拒绝。
(2)await:await 关键字用于暂停异步函数的执行,等待 Promise 对象解决,然后返回解决的结果。await 只能在异步函数内部使用
async、await 的优势
async、await 基本用法:
await 到底在等啥?
10. 模块化
导入和导出
模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。
模块化的优势有以下几点:1)防止命名冲突 2)代码复用 3)高维护性
模块功能主要由两个命令构成: export 和 import。export 命令用于规定模块的对外接口 import 命令用于输入其他模块提供的功能
ES6 模块与 CommonJS 模块有什么异同?
11. 迭代器和生成器
ES6 中引入了迭代器和生成器的概念,可以简化处理集合和异步编程的复杂度。迭代器是一个包含 next()方法的对象,可以按照定义的顺序逐个返回值。而生成器是一种特殊的函数,可以通过 yield 关键字将状态保存下来,并在需要的时候恢复执行。
12. Map 和 Set 数据结构
Set(集合)
ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯一的,集合的属性和方法:
size 返回集合的元素个数
add 增加一个新元素,返回当前集合
delete 删除元素,返回 boolean 值
has 检测集合中是否包含某个元素,返回 boolean 值
map(字典)
ES6 提供 Map 数据结构。它类似于对象,也是键值对的集合。但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 的属性和方法:
size 返回 Map 的元素个数
set 增加一个新元素,返回当前 Map
get 返回键名对象的键值
has 检测 Map 中是否包含某个元素,返回 boolean 值
clear 清空集合,返回 undefined
set 和 map 的区别?
共同点:集合、字典都可以存储不重复的值
不同点:集合是以[值,值]的形式存储元素,字典是以[键,值]的形式存储
map 和 Object 的区别
map 和 weakMap 的区别
13. Symbol
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。
特点:
Symbol 的值是唯一的,用来解决命名冲突的问题
Symbol 值不能与其他数据进行运算
Symbol 定义的对象属性不能使用 for…in 循环遍历,但是可以使用 Reflect.ownKeys 来获取对象的所有键名
Symbol 值不能与其他类型的值进行运算,会报错,但是,Symbol 值可以显式转为字符串,另外,Symbol 值也可以转为布尔值,但是不能转为数值。
14. 字符串新增的方法
includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
repeat():repeat 方法返回一个新字符串,表示将原字符串重复 n 次。
padStart():用于头部补全。
padEnd():用于尾部补全。
trimStart():清除字符串左边的空白。
trimEnd():清除字符串右边的空白。
replaceAll():可以一次性替换所有匹配。
at():接受一个整数作为参数,返回参数指定位置的字符,支持负索引(即倒数的位置)
15. 数组新增的方法
Array.from(): 从一个类似数组或可迭代对象中创建一个新的数组实例。
Array.of():用于将一组值,转换为数组。
fill(): 用一个固定值填充数组。
forEach(),map(),filter(),reduce() 和 reduceRight(): 提供高级的迭代方法。
sort(): 对数组的元素进行排序。
find():用于找出第一个符合条件的数组成员,如果没有找到返回 undefined。
findIndex():用于找出第一个符合条件的数组成员的位置,如果没有找到返回-1。
includes():表示某个数组是否包含给定的值,返回布尔值。
entries(),keys() 和 values(): 返回数组的迭代器,分别用于遍历键值对、键和值。
flat():将多维数组转化为低位数组。
flatMap():将多维数组转化为低位数组。
at():接受一个整数作为参数,返回对应位置的成员,并支持负索引。这个方法不仅可用于数组,也可用于字符串和类型数组(TypedArray)。
16.对象新增的方法
object.keys()方法返回一个给定对象的所有的键
object.values()方法返回一个给定对象的所有的值
object.entries()方法返回一个给定对象自身可遍历属性 [key,value] 的数组
Object.fromEntries()方法是 Object.entries()的逆操作,用于将一个键值对数组转为对象。
object.assign()方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)
17.类数组对象的定义?
为什么函数的 arguments 参数是类数组而不是数组?如何遍历类数组?
类数组对象的理解,如何转化为数组
18.数组的遍历方法有哪些
forEach 和 map 方法有什么区别
如何使用 for…of 遍历对象
for…in 和 for…of 的区别
19. ajax、axios、fetch
对 ajax 的理解,实现一个 ajax 请求
AJAX 全称(Async Javascript and XML),即异步的JavaScript 和XML,是一种创建交互式网页应用的网页开发技术,可以在不重新加载整个网页的情况下,与服务器交换数据,并且更新部分网页。
Ajax 的原理简单来说通过XmlHttpRequest 对象来向服务器发异步请求,从服务器获得数据,然后用JavaScript 来操作DOM 而更新页面。
实现 Ajax 异步交互需要服务器逻辑进行配合,需要完成以下步骤:
创建 Ajax 的核心对象 XMLHttpRequest 对象
通过 XMLHttpRequest 对象的 open() 方法与服务端建立连接
构建请求所需的数据内容,并通过XMLHttpRequest 对象的 send() 方法发送给服务器端
通过 XMLHttpRequest 对象提供的 onreadystatechange 事件监听服务器端你的通信状态
接受并处理服务端向客户端响应的数据结果
将处理结果更新到 HTML 页面中
axios 的使用
发送请求
import axios from 'axios';
axios(config); // 直接传入配置
axios(url[, config]) // 传入 url 和配置
axios[method](url[, option]) // 直接调用请求方式方法,传入 url 和配置
axios[method](url[, data[, option]]) // 直接调用请求方式方法,传入 data、url 和配置
axios.request(option) // 调用 request 方法
const axiosInstance = axios.create(config) // axiosInstance 也具有以上 axios 的能力
axios.all([axiosInstance1, axiosInstance2]).then(axios.spread(response1, response2)) // 调用 all 和传入 spread 回调
请求拦截器
axios.interceptors.request.use(function (config) { // 这里写发送请求前处理的代码
return config;
},
function (error) { // 这里写发送请求错误相关的代码
return Promise.reject(error);
});
响应拦截器
axios.interceptors.response.use(function (response) { // 这里写得到响应数据后处理的代码
return response;
},
function (error) { // 这里写得到错误响应处理的代码
return Promise.reject(error);
});
取消请求
// 方式一
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('xxxx', { cancelToken: source.token }) // 取消请求 (请求原因是可选的)
source.cancel('主动取消请求');
// 方式二
const CancelToken = axios.CancelToken; let cancel; axios.get('xxxx', {
cancelToken: new CancelToken(function executor(c) { cancel = c; })
});
cancel('主动取消请求');