四、ES6中的对象的增强
如果kv一致,此时可以省略v
let a = 100; let obj = { a , b : 200, c : 300 }; console.log(obj);
[]现在可以出现在{}中,表示变量key: var str = "name"; var obj = { [str] : "小明", age : 10, sex : "男" } console.log(obj.name); 合并对象: var target = { a: 1 }; var source1 = { b: 2 }; var source2 = { c: 3 }; Object.assign(target, source1, source2); console.log(target) // {a:1, b:2, c:3} 得到对象的所有键: var obj = {"a" : 1 , "b" : 2 , "c" : 3}; console.log(Object.keys(obj)); 来一个例子: var obj = {"a" : 1 , "b" : 2 , "c" : 3}; var keys = Object.keys(obj); for(let k of keys){ console.log(k); } for(let k in obj){ console.log(k); }
五、ES6中的Symbol类型
ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,前六种是:Undefined、Null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
let s = Symbol(); console.log(typeof s); //symbol 加上参数: let s = Symbol("哈哈"); console.log(s); console.log(typeof s);
Symbol()类型的值,可以当做对象的key: var str = Symbol(); var obj = { [str] : 10 } console.log(obj[str]); //10
六、ES6中的Set和Map数据结构
Set是不能有重复项的数组,Map是可以用引用类型值当做key的对象。
Set是集合的意思,集合中不能有重复元素,高中学习的。
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
let s = new Set(); s.add(1); s.add(2); s.add(3); s.add(3); s.add(4); s.add(4); s.add(5); console.log(s); // Set {1,2,3,4,5} console.log(typeof s); //object for(let v of s){ console.log(v); }
实例化的时候就可以直接传入数组,此时类似数组的去重。这是数组去重的最快的方法。
let s = new Set([1,1,1,1,1,2,2,2,2]); console.log(s); // Set{1,2} for(let v of s){ console.log(v); //1,2 } console.log([...s]); //[1,2]
数组去重的最快的办法:
let arr = [1,23,34,3,3,3,324,23,3,34,34,324]; arr = [...new Set(arr)] console.log(arr);
size属性表示集合的长度:
let s = new Set([1,1,1,1,1,2,2,2,2]); console.log(s.size); //2
Map是映射的意思,通常情况下,obj只能用基本类型值当做key。不能用xiaoming当做key。
new Map()的时候用数组表示映射关系,人家要求的:
var xiaoming = {"name" : "小明" , "age" : 12 , "sex" : "男"}; var xiaohong = {"name" : "小红" , "age" : 13 , "sex" : "女"}; var xiaoqiang = {"name" : "小强" , "age" : 14 , "sex" : "男"}; var m = new Map([ [xiaoming , "好人"], [xiaohong , "坏人"], [xiaoqiang , "好人"] ]); m.set(xiaoqiang,"坏人"); //设置xiaoqiang对象映射到"坏人" console.log(m); console.log(m.get(xiaoming));
类似于传统对象:
const yuefenmap = new Map([ ["一月","Jan"], ["二月","Feb"], ["三月","Mar"] ]); console.log(yuefenmap); let a = yuefenmap.get("三月"); console.log(a);
和PHP中的别名数组来类比。
七、ES6中的Promise对象
这是ES6中增加的一个处理异步的对象。
传统编程写异步函数的时候,经常遇见回调套回调:
fs.readFile("",function(err,results){ User.find({"email" : results[0].email},function(){ }); });
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,可以调用then方法表示异步语句执行之后做的事情,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise对象有以下两个特点。
(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
基本语法:
var promise = new Promise(function(resolve, reject){ if(异步语句){ resolve(value); }else{ reject(err); } }); promise.then(function(value) { // success }, function(error) { // failure }); 来举个例子(注意Promise用的时候特别简单), 比如有一个需求就是2秒钟之后输出你好,再两秒钟之后输出我也好,再2秒钟之后输出那就好: 传统做法就是回调函数: function timeout(ms,callback){ setTimeout(callback,ms); } timeout(2000,function(){ console.log("你好"); timeout(2000,function(){ console.log("我也好"); timeout(2000,function(){ console.log("那就好"); }); }); }); 再来一个例子,读取完test.txt然后读取text1.txt: var fs = require("fs"); function read(url){ return new Promise(function(resolve,reject){ fs.readFile(url,function(err,data){ resolve(data.toString()); }); }); } read("./test.txt") .then(function(data){ console.log(data); }) .then(function(){ read("./test2.txt").then(function(data){ console.log(data); }); });
无非就是将回调函数换了一种方法写出来了,原来一个异步函数是要传入callback的,但是现在一个异步函数可以返回一个Promise对象,此时就不需要传入callback了。
.then().then().then()语法好看,简单清晰。
小案例图片加载(来自:http://es6.ruanyifeng.com/#docs/promise) <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div id="box"></div> <script type="text/javascript"> function loadPic(url){ return new Promise(function(resolve,reject){ var img = new Image(); img.onload = function(){ resolve(img); } img.onerror = function(){ reject(new Error("加载错误")); } img.src = url; }); } loadPic("0.jpg").then(function(img){ document.getElementById("box").appendChild(img); },function(err){ alert("失败!"); }) </script> </body> </html>
Promise实例具有then方法,也就是说,then方法是定义在原型对象。then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。
JS中有一个try...catch()...语句,用途是捕获异常,表示如果有异常语句的话,让异常语句抑制错误不要向控制台输出,不要终止程序执行,而是执行catch里面的语句。
try{ throw new Error("错误") }catch(exp){ console.log("有错误"); } console.log("A");
异常语句如果在try..catch..中,不会终止程序的运行。
try..catch..不是用来调试的语句,而是程序员明确知道这里可能会发生一些错误,而用的“备选方案”。
比如添加事件监听,可以用能力检测,也可以用try..catch..
var box = document.getElementById("box"); try{ box.addEventListener("click", function(){ alert("我是addEventListener添加的click事件"); }, false); }catch(exp){ box.attachEvent("onclick", function(){ alert("我是attachEvent添加的click事件"); }); } 但是try..catch..不能捕获异步的异常: try{ setTimeout(function(){ throw new Error("错误"); },2000); }catch(exp){ console.log("BBB"); } console.log("A");
BBB是不能输出的,控制台还是会收到错误信息。
ES6中Promise对象的实例提供了catch()方法,表示捕获异常。
function getInfo(){ return new Promise(function(resolve,reject){ setTimeout(resolve,2000); }); } getInfo().then(function(){ throw new Error(""); }).catch(err => { console.log("捕获到了异常"); });
Promise.all(数组)表示数组中的Promise实例都执行完毕之后做的事情。all()函数也返回一个Promise对象,所以也可以调用then方法,then方法接受实参为posts,表示数组中所有的promise对象resolve的实参组成的数组。
var fs = require("fs"); function getJson(url){ return new Promise(function(resolve,reject){ fs.readFile(url,function(err,data){ if(err){ reject(err); return; } resolve(data.toString()); }) }); } var arr = [1,2,3]; var promises = arr.map(function(item){ //item会依次成为1,2,3 return getJson("./test" + item + ".txt"); }); Promise.all(promises).then(function(posts){ console.log("都读取完毕"); console.log(posts); });
Promise.resolve() 有时需要将现有对象转为Promise对象,Promise.resolve方法就起到这个作用
var jsPromise = Promise.resolve($.ajax('/whatever.json'));
需要注意的是resolve()函数里面放置必须是异步函数。
再来一个例子,比如mongoose中可以封装一个Promise的静态方法:
userSchema.static.findById = function(id){ var self = this; return new Promise(function(resolve,reject){ self.find({id : id} , function(err,results){ resolve(results); }); }); }
中间件的调用:
exports.showStudentById = function(req,res){ User.findById(id).then(function(results){ }); }