1、var、let、const之间的区别
变量提升:const和let不存在变量提升情况;var存在变量提升情况。暂时性死区:let, const存在暂时性死区 (只有等到声明变量的那一行代码出现,才可以获取和使用该变量);var由于有变量提升,所以不存在这种情况。块级作用域:let, const存在块级作用域;var只有函数作用域和全局作用域。重复声明:const、let不可以重复声明变量;var 可以重复声明(指的是同一作用域下重复声明)。修改声明的变量:var、 let 可以修改变量(指的是修改变量指向的内存地址,简单类型就是变量本身),const不能修改变量。
- 另外能用
const的情况尽量使用const,其他情况下大多数使用let,避免使用var。
2、箭头函数,跟普通函数的区别
箭头函数的特点:
- 使用“箭头”(=>)定义函数
- 如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分
- 如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用
return语句返回 - 不可以使用
new关键字创建实例对象 - 函数体内的
this对象,就是定义时所在的对象,而不是使用时所在的对象,且不可以修改this的值 - 不可以当作构造函数,也就是说,不可以使用
new命令,原因是没有构造器constructor - 不可以使用
arguments对象,该对象在函数体内不存在 - 不可以使用
yield命令,因此箭头函数不能用作 Generator 函数
3、ES6对数组新增了哪些扩展
1. 关于构造函数:
Array.from()将两类对象转为真正的数组:类似数组的对象和可遍历(iterable)的对象(包括ES6新增的数据结构Set和Map)Array.of()用于将一组值,转换为数组。没有参数的时候,返回一个空数组;当参数只有一个的时候,实际上是指定数组的长度;参数个数不少于 2 个时,才会返回由参数组成的新数组。
2. 实例对象新增的方法:
find()用于找出第一个符合条件的数组成员findIndex返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1findLast用于找出最后一个符合条件的数组成员findLastIndex返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1fill()使用给定值,填充一个数组,还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置keys()是对键名的遍历values()是对键值的遍历entries()是对键值对的遍历includes()用于判断数组是否包含给定的值(可以判断NaN)flat()将数组扁平化处理,返回一个新数组,对原数据没有影响
3. 数组的空位:
- ES6 则是明确将空位转为
undefined
4. 排序稳定性:
- 将
sort()默认设置为稳定的排序算法,指的是排序关键字相同的项目,排序前后的顺序不变。
4、ES6对对象新增了哪些扩展?
1. 属性的简写:
- 当对象键名与对应值名相等的时候,可以进行简写;方法也能简写,不过简写的对象方法不能用作构造函数,否则会报错
2. super关键字
- 新增了另一个类似的关键字
super,指向当前对象的原型对象
3. 属性的遍历
- 一共有 6 种方法可以遍历对象的属性:for...in、Object.keys(obj)、Object.getOwnPropertyNames(obj)、Object.getOwnPropertySymbols(obj)、Reflect.ownKeys(obj)
4. 对象新增的方法
Object.is()严格判断两个值是否相等,与严格比较运算符(===)的行为基本一致,不同之处只有两个:一是+0不等于-0,二是NaN等于自身Object.assign()方法用于对象的合并,将源对象source的所有可枚举属性,复制到目标对象target,方法的第一个参数是目标对象,后面的参数都是源对象Object.keys()返回自身的(不含继承的)所有可遍历(enumerable)属性的键名的数组Object.values()返回自身的(不含继承的)所有可遍历(enumerable)属性的值的数组Object.entries()返回一个对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对的数组Object.fromEntries()用于将一个键值对数组转为对象
5. 属性名表达式
- 允许字面量定义对象时,将表达式放在括号内,表达式还可以用于定义方法名
5、对ES6新增Set、Map两种数据结构的理解
Set
Set:类似于数组,但是成员的值都是唯一的,没有重复的值,我们一般称为集合。Set本身是一个构造函数,用来生成 Set 数据结构。- Set 实例的属性和方法
add()添加某个值,返回 Set结构本身,当添加实例中已经存在的元素,set不会进行处理添加delete()删除某个值,返回一个布尔值,表示删除是否成功has()返回一个布尔值,判断该值是否为Set的成员clear()清除所有成员,没有返回值size返回set的长度
- 遍历操作
- keys():返回键名的遍历器
- values():返回键值的遍历器
- entries():返回键值对的遍历器
- forEach():使用回调函数遍历每个成员
Map
Map类型是键值对的有序列表,而键和值都可以是任意类型。Map本身是一个构造函数,用来生成 Map数据结构- Map实例的属性和方法
- size 属性:
- set():
- get():
- has():
- delete():
- clear():
- 遍历操作、
-
keys():返回键名的遍历器
-
values():返回键值的遍历器
-
entries():返回所有成员的遍历器
-
forEach():遍历 Map 的所有成员
-
共同点:集合、字典都可以存储不重复的值;本身是一个构造函数共同遍历方法
6、ES6中模块化
是能够单独命名并独立地完成一定功能的程序语句的集合
1. 特点
- 1、ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
- 2、ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。
- 3、“编译时加载”或者称为静态加载,使得静态分析成为可能,比如引入宏(macro)和类型检验(type system)
- 4、将来浏览器的新 API 就能用模块格式提供,不再必须做成全局变量或者navigator对象的属性。
- 5、ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict"
- 6、一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。
- 7、import命令输入的变量都是只读的,因为它的本质是输入接口。也就是说,不允许在加载模块的脚本里面,改写接口
2. Module的加载实现
- 1、默认情况下:浏览器同步加载js脚本,即渲染引擎遇到script标签就会停下来,等执行完脚本再继续向下渲染,如果是外部脚本就要先下载
- 2、异步加载:渲染引擎遇到这一行命令,就会开始下载外部脚本,但不会等它下载和执行,而是直接执行后面的命令。有两种方式 defer或async属性, defer:“渲染完再执行”,async:“下载完就执行”。
- 3、es6模块加载:type="module" 浏览器是异步加载模块的,等同于type="defer"
3. ES6 模块与 CommonJS 模块的差异
- 1、CommonJS 模块输出的是一个值的拷贝(一旦输出这个值,模块内部的变化就影响不到它),ES6 模块输出的是值的引用。
- 2、CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
- 3、CommonJS 模块的require()是同步加载模块,ES6 模块的import命令是异步加载,有一个独立的模块依赖的解析阶段。
- 4、CommonJS 模块的顶层this指向当前模块,ES6 模块之中顶层的this指向undefined
4. 循环加载
“循环加载”(circular dependency)指的是,a脚本的执行依赖b脚本,而b脚本的执行又依赖a脚本
7、ES6中Promise及使用场景?
Promise对象是一个构造函数,用来生成Promise实例
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject
当开发有异步操作时,就可以给异步操作包装一个promise
异步操作后会有三种状态:
- Pending:初始状态/等待状态,比如正在执行网络请求,或者定时器没有到时间
- fulfilled:满足状态,当我们主动回调了resolve时,就处于该状态,并且会回调.then()
- Rejected:拒绝状态,当我们主动回调了reject时,就处于该状态,并且会回调.catch()
- 对象的状态不受外界影响,只有异步操作的结果,可以决定当前是哪一种状态
一旦状态改变(从
pending变为fulfilled和从pending变为rejected),就不会再变,任何时候都可以得到这个结果。 流程图:static.vue-js.com/1b02ae90-58…
Promise构建出来的实例存在以下方法:
- then() 成功时执行
- catch() 失败时执行
- finally() 无论如何都会执行
构造函数方法
- all():同样是将多个 Promise 实例,包装成一个新的 Promise 实例。全部状态是fulfilled才会返回fulfilled
- race():同样是将多个 Promise 实例,包装成一个新的 Promise 实例。有一个实例率先改变状态,
p的状态就跟着改变 - allSettled():
- resolve():
参数可以分成四种情况,分别如下:
参数是一个 Promise 实例,
promise.resolve将不做任何修改、原封不动地返回这个实例 参数是一个thenable对象,promise.resolve会将这个对象转为Promise对象,然后就立即执行thenable对象的then()方法 参数不是具有then()方法的对象,或根本就不是对象,Promise.resolve()会返回一个新的 Promise 对象,状态为resolved没有参数时,直接返回一个resolved状态的 Promise 对象 - reject():方法也会返回一个新的 Promise 实例,该实例的状态为
rejected - try()
使用场景
- 将图片的加载写成一个
Promise,一旦加载完成,Promise的状态就发生变化 - 过链式操作,将多个渲染数据分别给个
then,让其各司其职。或当下个异步请求依赖上个请求结果的时候,我们也能够通过链式操作友好解决问题 - 通过
all()实现多个请求合并在一起,汇总所有请求结果,只需设置一个loading即可 - 通过
race可以设置图片请求超时
8、ES6中的Generator及使用场景?
ES6 提供的一种异步编程解决方案。遍历器对象,可以依次遍历 Generator 函数内部的每一个状。形式上,Generator 函数是一个普通函数,但是有两个特征:
function关键字与函数名之间有一个星号- 函数体内部使用
yield表达式,定义不同的内部状态
运行逻辑如下
- 遇到
yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。返回的对象中value对应状态值,done用来判断是否存在下个状态 - 通过
next方法才会遍历到下一个内部状态。下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式。通过调用next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值 - 如果没有再遇到新的
yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。 - 如果该函数没有
return语句,则返回的对象的value属性值为undefined
使用场景
- 异步解决方案
- 回调函数
- Promise 对象
- generator 函数
- async/await
- 区别
promise和async/await是专门用于处理异步操作的Generator并不是为异步而设计出来的,它还有其他功能(对象迭代、控制输出、部署Interator接口)promise编写代码相比Generator、async更为复杂化,且可读性也稍差Generator、async需要与promise对象搭配处理异步情况async实质是Generator的语法糖,相当于会自动执行Generator函数async使用上更为简洁,将异步代码以同步的形式进行编写,是处理异步编程的最终方案
9、ES6中Proxy的及使用场景?
Proxy为 构造函数,用来生成 Proxy 实例。
target表示所要拦截的目标对象(任何类型的对象,包括原生数组,函数,甚至另一个代理)
handler通常以函数作为属性的对象,用来定制拦截行为
proxy实例方法
Proxy 支持的拦截操作一共有 13 种。
- get()
- 拦截读取操作,可以接受三个参数。依次为目标对象、属性名和 proxy 实例本身(严格地说,是操作行为所针对的对象),其中最后一个参数可选。
- 如果一个属性不可配置(configurable)且不可写(writable),则 Proxy 不能修改该属性,否则会报错
- set()
- 拦截某个属性的赋值操作,可以接受四个参数,依次为目标对象、属性名、属性值和 Proxy 实例本身,其中最后一个参数可选。
- 如果目标对象自身的某个属性,不可写且不可配置,那么
set方法将不起作用
使用场景
Proxy其功能非常类似于设计模式中的代理模式,常用功能如下:
- 拦截和监视外部对对象的访问
- 降低函数或类的复杂度
- 在复杂操作前对操作进行校验或对所需资源进行管理
reflect
- 1、将Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上
- 2、修改某些Object方法的返回结果,让其变得更合理
- 3、让Object操作都变成函数行为。
- 4、Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。
- 也就是说,不管Proxy怎么修改默认行为,你总可以在Reflect上获取默认行为。
- Reflect对象一共有 13 个静态方法。