前言
ES6增加了不少新特性,下面继续整理了一下比较常用的新特性。
- Set
- Map
- Promise
- Class
- Module
Set
- Set类似于数组,但是成员的值都是唯一的,没有重复的值。
Set实例的增删改查方法
- add(value):添加某个值,返回 Set 结构本身。
- delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
- has(value):返回一个布尔值,表示该值是否为Set的成员。
- clear():清除所有成员,没有返回值。
{
let arr=['add','delete','clear','has'];
let list=new Set(arr);
console.log('has',list.has('add')); //has true
console.log('delete',list.delete('add'),list);
// delete true Set(3) {"delete", "clear", "has"}
list.clear();
console.log('list',list);
//list Set(0){}
}
Set结构的实例有四个遍历方法,可以用于遍历成员。
keys():返回键名的遍历器
values():返回键值的遍历器
entries():返回键值对的遍历器
forEach():使用回调函数遍历每个成员
{
let arr=['add','delete','clear','has'];
let list=new Set(arr);
for(let key of list.keys()){
console.log('keys',key);
// keys add
// keys delete
// keys clear
// keys has
}
for(let value of list.values()){
console.log('value',value);
//value add
//value delete
//value clear
//value has
}
for(let [key,value] of list.entries()){
console.log('entries',key,value);
//entries add add
//entries delete delete
//entries clear clear
//entries has has
}
list.forEach(function(item){console.log(item);})
//add delete clear has
}
去除数组的重复成员
{
let arr = [1,2,3,3,5,4,4,5];
let list = new Set(arr);
console.log(list);
//Set(5) {1, 2, 3, 5, 4}
}
Map
- JavaScript 的对象(Object),本质上是键值对的集合(Hash结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。
- ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
- Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应
- 如果你需要“键值对”的数据结构,Map 比 Object 更合适。
{
let map = new Map();
let arr=['123'];
map.set(arr,456);
console.log('map',map,map.get(arr));
//map Map(1) {Array(1) => 456} 456
}
Map 结构的实例有以下属性和操作方法。
- size属性返回 Map 结构的成员总数。
- set方法设置键名key对应的键值为value,然后返回整个 Map结构。如果key已经有值,则键值会被更新,否则就新生成该键。set方法返回的是当前的Map对象,因此可以采用链式写法。
- get方法读取key对应的键值,如果找不到key,返回undefined。
- has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。
- delete方法删除某个键,返回true。如果删除失败,返回false。
- clear方法清除所有成员,没有返回值。
Map的遍历方法同Set
Map Set Array Object数据结构对比
- map与array增删改查对比
{
let map=new Map();
let array=[];
// 增
map.set('t',1);
array.push({t:1});
console.info('map-array',map,array);
// 查
let map_exist=map.has('t');
let array_exist=array.find(item=>item.t);
console.info('map-array',map_exist,array_exist);
// 改
map.set('t',2);
array.forEach(item=>item.t?item.t=2:'');
console.info('map-array-modify',map,array);
// 删
map.delete('t');
let index=array.findIndex(item=>item.t);
array.splice(index,1);
console.info('map-array-empty',map,array);
}
- set和array的对比
{
let set=new Set();
let array=[];
// 增
set.add({t:1});
array.push({t:1});
console.info('set-array',set,array);
// 查
let set_exist=set.has({t:1});
let array_exist=array.find(item=>item.t);
console.info('set-array',set_exist,array_exist);
// 改
set.forEach(item=>item.t?item.t=2:'');
array.forEach(item=>item.t?item.t=2:'');
console.info('set-array-modify',set,array);
// 删
set.forEach(item=>item.t?set.delete(item):'');
let index=array.findIndex(item=>item.t);
array.splice(index,1);
console.info('set-array-empty',set,array);
}
- map,set,object对比
{
let item={t:1};
let map=new Map();
let set=new Set();
let obj={};
// 增
map.set('t',1);
set.add(item);
obj['t']=1;
console.info('map-set-obj',obj,map,set);
// 查
console.info({
map_exist:map.has('t'),
set_exist:set.has(item),
obj_exist:'t' in obj
})
// 改
map.set('t',2);
item.t=2;
obj['t']=2;
console.info('map-set-obj-modify',obj,map,set);
// 删除
map.delete('t');
set.delete(item);
delete obj['t'];
console.info('map-set-obj-empty',obj,map,set);
}
建议性总结
- 能使用map,就不使用数组和object,如需保证数据的唯一性,考虑使用set。
Promise
Promise 是异步编程的一种解决方案
- 对象的状态不受外界影响。
Promise
对象的三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。- 一旦状态改变,就不会再变,任何时候都可以得到这个结果。
- Promise 实例具有
then
方法,then
方法的第一个参数是resolved
状态的回调函数,第二个参数(可选)是rejected
状态的回调函数。
ES5异步写法与ES6的Promise写法
//ES5写法
{
// 基本定义
let ajax=function(callback){
console.log('ES5执行');
setTimeout(function () {
callback&&callback.call()
}, 1000);
};
ajax(function(){
console.log('ES5:timeout');
})
}
//ES6写法
{
let ajax=function(){
console.log('执行2');
return new Promise(function(resolve,reject){
setTimeout(function () {
resolve()
}, 1000);
})
};
ajax().then(function(){
console.log('promise','timeout2');
})
}
//ES6多个异步
{
let ajax=function(){
console.log('执行3');
return new Promise(function(resolve,reject){
setTimeout(function () {
resolve()
}, 1000);
})
};
ajax()
.then(function(){
return new Promise(function(resolve,reject){
setTimeout(function () {
resolve()
}, 2000);
});
})
.then(function(){
console.log('timeout3');
})
}
- Promise 新建后立即执行,然后
then
方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行。 - 从上面的例子可以看出,相对于ES5而言,ES6的Promise避免了回调地狱,并且代码阅读性很高,后期维护可以很轻松看清楚异步函数的先后顺序。
catch
Promise.prototype.catch
方法是.then(null, rejection)
的别名,用于指定发生错误时的回调函数。
{
let ajax=function(num){
console.log('执行4');
return new Promise(function(resolve,reject){
if(num>5){
resolve()
}else{
throw new Error('出错了')
}
})
}
ajax(6).then(function(){
console.log('log',6);
}).catch(function(err){
console.log('catch',err);
});
ajax(3).then(function(){
console.log('log',3);
}).catch(function(err){
console.log('catch',err); //catch Error: 出错了
});
}
all
Promise.all
方法创建的实例只有在接收的参数状态全部为fulfilled
时,Promise.all
方法包装的实例才会变为fulfilled
, 或者之中有一个被rejected
,该实例才会变为rejected
。此时第一个被reject
的实例的返回值,会传递给Promise.all
方法创建实例的回调函数。
{
// 所有图片加载完再添加到页面
function loadImg(src){
return new Promise((resolve,reject)=>{
let img=document.createElement('img');
img.src=src;
img.onload=function(){
resolve(img);
}
img.onerror=function(err){
reject(err);
}
})
}
function showImgs(imgs){
imgs.forEach(function(img){
document.body.appendChild(img);
})
}
Promise.all([
loadImg('2.png'),
loadImg('ba.png'),
loadImg('c.png')
]).then(showImgs)
//只有当3个实例的状态都变成fulfilled,或者其中有一个变为rejected,才会调用Promise.all方法后面的回调函数。
}
race
Promise.race
方法的参数与Promise.all
方法一样,如果不是 Promise 实例,就会先调用Promise.resolve
方法,将参数转为 Promise 实例,再进一步处理。
{
// 有一个图片加载完就添加到页面
function loadImg(src){
return new Promise((resolve,reject)=>{
let img=document.createElement('img');
img.src=src;
img.onload=function(){
resolve(img);
}
img.onerror=function(err){
reject(err);
}
})
}
function showImgs(img){
let p=document.createElement('p');
p.appendChild(img);
document.body.appendChild(p)
}
Promise.race([
loadImg('32.png'),
loadImg('a.png'),
loadImg('bc.png')
]).then(showImgs)
}
Class
- ES6 的
class
可以让对象原型的写法更加清晰、更像面向对象编程的语法。 - Class 可以通过
extends
关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。
{
// 基本定义和生成实例
class Parent{
constructor(name='wang'){
this.name=name;
}
}
let v_parent=new Parent('v');
console.log('构造函数和实例',v_parent); //构造函数和实例 Parent {name: "v"}
}
{
// 继承
class Parent{
constructor(name='wang'){
this.name=name;
}
}
class Child extends Parent{
}
console.log('继承',new Child()); //继承 Child {name: "wang"}
}
{
// 继承传递参数
class Parent{
constructor(name='wang'){
this.name=name;
}
}
class Child extends Parent{
constructor(name='child'){
this.color = "color"; // ReferenceError
super(name); //super必须在最前面调用
this.type='child'; //正确
}
}
console.log('继承传递参数',new Child('hello'));
// 继承传递参数 Child {name: "hello", type: "child"}
}
ES5 的继承,实质是先创造子类的实例对象
this
,然后再将父类的方法添加到this
上面(Parent.apply(this)
)。ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this
上面(所以必须先调用super
方法),然后再用子类的构造函数修改this
。
与 ES5 一样,在“类”的内部可以使用
get
和set
关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。
{
// getter,setter
class Parent{
constructor(name='wang'){
this.name=name;
}
get longName(){
return 'mk'+this.name
}
set longName(value){
this.name=value;
}
}
let v=new Parent();
console.log('getter',v.longName); //getter mkwang
v.longName='hello';
console.log('setter',v.longName); // setter mkhello
}
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上
static
关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。如果静态方法包含
this
关键字,这个this
指的是类,而不是实例。
{
// 静态方法
class Parent{
constructor(name='wang'){
this.name=name;
}
static tell(){
console.log('tell'); //tell
}
}
Parent.tell();
}
{
// 静态属性
class Parent{
constructor(name='wang'){
this.name=name;
}
static tell(){
console.log('tell'); //tell
}
}
Parent.type='test';
console.log('静态属性',Parent.type); //静态属性 test
}
Module模块化
模块功能主要由两个命令构成:export
和import
。export
命令用于规定模块的对外接口,import
命令用于输入其他模块提供的功能。
// 需要导出的模块文件
let A=123;
let test=function(){
console.log('test');
}
class Hello{
test(){
console.log('class');
}
}
export default {
A,
test,
Hello
}
//在其他文件中引入导出的模块
import Module from '../Module.js';
参考
版权属于:Sanakey(特殊声明除外)
本文链接:https://keymoe.com/archives/18/
所有原创文章采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。 您可以自由的转载和修改,但请务必注明文章来源并且不可用于商业目的。