ES6更新的内容主要分为以下几点
- 表达式:声明、解构赋值
- 内置对象:字符串扩展、数值扩展、对象扩展、数组扩展、函数扩展、正则扩展、Symbol、Set、Map、Proxy、Reflect
- 语句与运算:Class、Module、Iterator
- 异步编程:Promise、Generator、Async
-----------------------------------------------------------------
var、let、const之间的区别
1. var
在ES5中,顶层对象的属性和全局变量是等价的,用var声明的变量既是全局变量,也是顶层变量
注意:顶层对象,在浏览器环境指的是window对象,在 Node 指的是global对象
2. let
let是ES6新增的命令,用来声明变量
用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效
3.const
const声明一个只读的常量,一旦声明,常量的值就不能改变
三者区别可以围绕下面五点展开:
- 变量提升
- 暂时性死区
- 块级作用域
- 重复声明
- 修改声明的变量
- 使用
作用域
- 全局作用域
- 函数作用域:function() {}
- 块级作用域:{}
作用范围
var命令在全局代码中执行const命令和let命令只能在代码块中执行
赋值使用
const命令声明常量后必须立马赋值let命令声明变量后可立马赋值或使用时赋值
声明方法:var、const、let、function、class、import
Symbol
symbol是一种全新的基础数据类型,表示是唯一的值。symbol的值通过symbol( )函数创建。
let onlyValue = Symbol();
typeof onlyValue; // symbol
let onlyValue1 = Symbol(),
onlyValue2 = Symbol();
onlyValue1 === onlyValue2 // false
ES6中数组新增了哪些扩展
- 扩展运算符的应用
- 构造函数新增的方法
- 实例对象新增的方法
- 数组的空位
- 排序稳定性
ES6中对象新增了哪些扩展
- 属性的简写
- 属性名表达式
- super关键字
- 扩展运算符的应用
- 属性的遍历
- 对象新增的方法
ES6中函数新增了哪些扩展
- 参数
- 属性
- 作用域
- 严格模式
- 箭头函数
ES6中新增的Set、Map两种数据结构怎么理解
一、Set
Set是es6新增的数据结构,类似于数组,但是成员的值都是唯一的,没有重复的值,我们一般称为集合
Set本身是一个构造函数,用来生成 Set 数据结构
Set的实例关于增删改查的方法:
-
add()
-
delete()
-
has()
-
clear()
二、Map
Map类型是键值对的有序列表,而键和值都可以是任意类型
Map本身是一个构造函数,用来生成 Map 数据结构
Map 结构的实例针对增删改查有以下属性和操作方法:
- size 属性
- set()
- get()
- has()
- delete()
- clear()
怎么理解ES6中 Promise的?使用场景?
一、介绍
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise对象有以下两个特点。
(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
二、用法
ES6 规定,Promise对象是一个构造函数,用来生成Promise实例。
Promise构建出来的实例方法:
- then()
- catch()
- finally()
- all()
- race()
- allSettled()
- resolve()
- reject()
- try()
1.then
then是实例状态发生改变时的回调函数,第一个参数是resolved状态的回调函数,第二个参数是rejected状态的回调函数
then方法返回的是一个新的Promise实例,也就是promise能链式书写的原因
getJSON("/data.json").then(function(json) {
return json.post;
}).then(function(post) {
// ...
});
2.catch
catch()方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数
getJSON('/data.json').then(function(posts) {
// ...
}).catch(function(error) {
// 处理 getJSON 和 前一个回调函数运行时发生的错误
console.log('发生错误!', error);
});
Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止
getJSON('/post/data.json').then(function(post) {
return getJSON(post.commentURL);
}).then(function(comments) {
// some code
}).catch(function(error) {
// 处理前面三个Promise产生的错误
});
3.finally
finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
4.all
Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例
// 生成一个Promise对象的数组
const promises = [2, 3, 5, 7, 11, 13].map(function (id) {
return getJSON('/post/' + id + ".json");
});
Promise.all(promises).then(function (posts) {
// ...
}).catch(function(reason){
// ...
});
5.race
const p = Promise.race([
fetch('/resource-that-may-take-a-while'),
new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('request timeout')), 5000)
})
]);
p
.then(console.log)
.catch(console.error);
三、总结
promise解决异步操作的优点:
- 链式操作减低了编码难度
- 代码可读性明显增强
Promise对象是一个构造函数,用来生成Promise实例
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”
promise对象仅有三种状态
pending(进行中)fulfilled(已成功)rejected(已失败)
解构赋值
1.对象
let obj = {
names:'张三',
age : 18,
sex : '女',
data :[1,2,3,4,5],
details: {
nickName: "光脚思考",
address: "中国北京",
signature: "勿以善小而不为,勿以恶小而为之"
},
say : function(){
console.log('你好我是张三');
}
}
// 1. 解构对象中的变量
let {names, age, status = "offline", details: { signature }, say} = obj;
console.log(names, age, status, signature);
let {
data : [a,b,c]
} = obj;
// 2. 解构对象中的方法
say();
2.数组
let [a, b, d] = [1, [2, 3], 4];
console.info(a);
console.info(b);
console.info(d);
3.函数
function add([x, y]){
return x + y;
}
add([1, 2]); // 3
4.循环中的解构赋值
let users = [
{
userName: "光脚丫思考1",
blog: "https://blog.csdn.net/gjysk",
},
{
userName: "光脚丫思考2",
blog: "https://blog.csdn.net/gjysk",
}
];
for (user of users) {
const { userName, blog } = user;
let message = `大家好,我是${userName},博客地址是:${blog}`;
console.info(message);
}
5.数值和布尔值
解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。
let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true
附加:developer.mozilla.org/zh-CN/docs/…
Proxy
介绍和使用
Proxy 是 ES6 为了操作对象引入的 API 。
Proxy 可以对目标对象的读取、函数调用等操作进行拦截,然后进行操作处理。它不直接操作对象,而是像代理模式,通过对象的代理对象进行操作,在进行这些操作时,可以添加一些需要的额外操作。
// 设 o 为房东,即被代理的对象
let o = {
name: 'Faker',
price: 200
}
// 设 d 为中介,即代理
let d = new Proxy(o, {})
console.log(d.price, d.name) // 200 'Faker'
// 因为传的是空对象,所以是透传
let d = new Proxy(o, {
get(target, key) { // target 是指被代理的对象 o,key 指的是 o 的属性
// 如果 key 为价格时进行加 10 的操作,否则返回 key 的值本身
if (key === 'price') {
return target[key] + 10
} else {
return target[key]
}
}
})
console.log(d.price, d.name) // 210 "Faker"
Proxy 实例的方法
handler解析
关于handler拦截属性,有如下:
- get(target,propKey,receiver):拦截对象属性的读取
- set(target,propKey,value,receiver):拦截对象属性的设置
- has(target,propKey):拦截
propKey in proxy的操作,返回一个布尔值 - deleteProperty(target,propKey):拦截
delete proxy[propKey]的操作,返回一个布尔值 - ownKeys(target):拦截
Object.keys(proxy)、for...in等循环,返回一个数组 - getOwnPropertyDescriptor(target, propKey):拦截
Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象 - defineProperty(target, propKey, propDesc):拦截
Object.defineProperty(proxy, propKey, propDesc),返回一个布尔值 - preventExtensions(target):拦截
Object.preventExtensions(proxy),返回一个布尔值 - getPrototypeOf(target):拦截
Object.getPrototypeOf(proxy),返回一个对象 - isExtensible(target):拦截
Object.isExtensible(proxy),返回一个布尔值 - setPrototypeOf(target, proto):拦截
Object.setPrototypeOf(proxy, proto),返回一个布尔值 - apply(target, object, args):拦截 Proxy 实例作为函数调用的操作
- construct(target, args):拦截 Proxy 实例作为构造函数调用的操作
1.get()
get方法用于拦截某个属性的读取操作,可以接受三个参数,依次为目标对象、属性名和 proxy 实例本身(严格地说,是操作行为所针对的对象),其中最后一个参数可选。
get方法的用法,上文已经有一个例子,下面是另一个拦截读取操作的例子。
var p = new Proxy(target, {
get: function(target, property, receiver) {
}
});
//target 目标对象 //property 获取的属性名 //receiver Proxy或者继承 Proxy 的对象
2.set()
set方法用来拦截某个属性的赋值操作,可以接受四个参数,依次为目标对象、属性名、属性值和 Proxy 实例本身,其中最后一个参数可选。
const p = new Proxy(target, {
set: function(target, property, value, receiver) {
}
});
//target 目标对象 //property 将被设置的属性名或 Symbol。value 新属性值 //receiver最初被调用的对象。通常是 proxy 本身,但 handler 的 set 方法也有可能在原型链上,或以其他方式被间接地调用(因此不一定是 proxy 本身)。
3.has()
has()方法用来拦截HasProperty操作,即判断对象是否具有某个属性时,这个方法会生效。典型的操作就是in运算符。
var p = new Proxy(target, {
has: function(target, prop) {
}
});
//target 目标对象 //prop 需要检查是否存在的属性。
4.apply()
apply方法拦截函数的调用、call和apply操作。
var p = new Proxy(target, {
apply: function(target, thisArg, argumentsList) {
}
});
//target 目标对象(函数) //thisArg 被调用时的上下文对象 //argumentsList 被调用时的参数数组。
Reflect
介绍
Reflect对象与Proxy对象一样,也是 ES6 为了操作对象而提供的新 API。
Reflect对象一共有 13 个静态方法。
- Reflect.apply(target, thisArg, args)
- Reflect.construct(target, args)
- Reflect.get(target, name, receiver)
- Reflect.set(target, name, value, receiver)
- Reflect.defineProperty(target, name, desc)
- Reflect.deleteProperty(target, name)
- Reflect.has(target, name)
- Reflect.ownKeys(target)
- Reflect.isExtensible(target)
- Reflect.preventExtensions(target)
- Reflect.getOwnPropertyDescriptor(target, name)
- Reflect.getPrototypeOf(target)
- Reflect.setPrototypeOf(target, prototype)
静态方法
get( )
查找并返回target对象的name属性,如果不存在此属性则返回undefined。如果target对象制定了getter,则receiver为getter指定的this值。第一个参数不是对象则报错。
let testObject = {
foo: 1,
bar: 2,
get baz() {
return this.foo + this.bar;
}
}
let testReceiverObject = {
foo: 3,
bar: 4
}
Reflect.get(testObject, 'foo'); // 1
Reflect.get(testObject, 'baz'); // 3
Reflect.get(testObject, 'baz', testReceiverObject); // 7
Reflect.get(1, 'baz'); // TypeError: Reflect.get called on non-object
set()
设置target对象的name属性等于value。如果name属性设置了赋值函数,则赋值函数的this绑定receiver。第一个参数不是对象则报错。
let testObject = {
foo: 1,
set bar(value) {
return this.foo = value;
}
}
let testReceiverObject = {
foo: 3
}
Reflect.set(testObject, 'foo', 4); // foo: 4
Reflect.set(testObject, 'bar', 4); // foo: 4
Reflect.set(testObject, 'foo', 1, testReceiverObject); // foo: 1
Reflect.set(1, foo); // TypeError: Reflect.set called on non-object
类(class)
class 的本质是 function。
它可以看作一个语法糖,让对象原型的写法更加清晰、更像面向对象编程的语法
class Example {
a = 3;
constructor() {
console.log(this.a);
}
}
new Example()
模块化(Module)
ES5不支持原生的模块化,在ES6中模块作为重要的组成部分被添加进来。模块的功能主要由 export 和 import 组成。每一个模块都有自己单独的作用域,模块之间的相互调用关系是通过 export 来规定模块对外暴露的接口,通过import来引用其它模块提供的接口。同时还为模块创造了命名空间,防止函数的命名冲突。
由于 ES6 模块是编译时加载,使得静态分析成为可能。有了它,就能进一步拓宽 JavaScript 的语法,比如引入宏(macro)和类型检验(type system)这些只能靠静态分析实现的功能。
除了静态加载带来的各种好处,ES6 模块还有以下好处。
- 不再需要
UMD模块格式了,将来服务器和浏览器都会支持 ES6 模块格式。目前,通过各种工具库,其实已经做到了这一点。 - 将来浏览器的新 API 就能用模块格式提供,不再必须做成全局变量或者
navigator对象的属性。 - 不再需要对象作为命名空间(比如
Math对象),未来这些功能可以通过模块提供。
导出(export)
1.导出变量
//test.js 1
export var name = 'zhangsan'
//test.js 2
var name = 'Rainbow';
var age = '24';
export {name, age};
2.导出函数
// moduleA.js
export function myModule(someArg) {
return someArg;
}
导入(import)
import {myModule} from 'myModule';// main.js
import {name,age} from 'test';// test.js
异步遍历器
介绍
异步遍历器是为解决同步遍历器 (iterator) 无法实现异步操作效果而产生的一种特殊遍历方式,主要区别与同步遍历器的地方在于 value 和 done 都是异步产生的,调用 next( ) 方法返回的是一个 promise 对象。
使用 then( ) 获取 promise 对象变成 resolve 以后的回调函数,该回调函数的参数是具有 value 和 done 两个属性的对象。
for await...of
在同步遍历器中使用 for...of 循环,在异步遍历器中使用 for await...of 进行循环,不过 for await...of 也可以用于同步遍历器。
async function test() {
for await (let i of asyncIteratorTest(['a', 'b'])) {
console.log(i);
}
}
异步 Generator 函数
异步的 Generator 函数返回的是一个 异步遍历器 对象。
async function* test() {
yield 'test';
}
const testObj = test();
testObj.next().then(item => {
console.log(item);
})