ES6新特性
1.变量扩展
(1).var 的问题:可以重复声明; 无法限制修改; 没有块级作用域;
(2).新加let: 不能重复声明; 变量—可以重新进行赋值; 块级作用域;
(3).新加const:不能重复声明; 常量—不可以重新进行赋值; 块级作用域;
//var a=1; //var a=2; //alert(a); //可以重复声明 //let a=1; //let a=2; //alert(a);//不可以重复声明 const a=1; const a=2; alert(a);//和let一样
块级作用域与函数声明
块级作用域有什么用?
<script> window.onload=function(){ var aBtn=document.getElementsByTagName("input"); for (var i=0;i<aBtn.length;i++) { aBtn[i].onclick=function() { alert(i); } } } </script> <input type="button" value="按钮1"> <input type="button" value="按钮2"> <input type="button" value="按钮3"> //都会弹出3
以前解决的办法:用密封空间:
<script> window.onload=function(){ var aBtn=document.getElementsByTagName("input"); for (var i=0;i<aBtn.length;i++) { (function(i){ //封密空间 aBtn[i].onclick=function() { alert(i); }; })(i); } } </script>
// 用一个封密空间,利用函数加了一级作用域。var 只认函数这一层。
现在:直接改成let即可:
<script> window.onload=function(){ var aBtn=document.getElementsByTagName("input"); for (let i=0;i<aBtn.length;i++) //本身就是一层作用域 { aBtn[i].onclick=function() { alert(i); }; } } </script> <input type="button" value="按钮1"> <input type="button" value="按钮2"> <input type="button" value="按钮3"> //把var 改成 let 即可,for循环就是一个语法块。
总结:let 完全可以取代const
2.函数扩展
(1)箭头函数
window.onload=function() { alert("abc") } window.onload=()=>{ alert("abc") }
箭头函数还有有两个特性:
- 如果只有一个参数,“()”小括号可以省;
- 如果只有一个return, “ { } ”花括号可以省;
/*let show=function(a){ return a*2; }*/ //可以简写成 let show=a=> a*2; alert(show(12))
(2)函数的参数
- 参数扩展/展开;
1.收集剩余参数, 形式:三个点,一个任意名字 ...args
function show(a,b,...args){ alert(a); alert(b); alert(args); } show(1,2,3,4,5,6) //1 //2 //3,4,5,6
2.展开数组:展开后的效果,相当于直接数组的内容写在这儿。
let arr1=[1,2,3]; let arr2=[5,6,8]; let arr=[...arr1,...arr2]; // let arr=[1,2,3,5,6,8]; 相当于这么写 alert(arr); //1,2,3,4,5,6,7,8
- 默认参数; ——传了听你的,不传听我的
function show(a,b=88,c=99){ console.log(a,b,c) } show(1,2) // 1,2,99
3.变量解构赋值
- 左右两边结构必须一样;
- 右边必须是个内容;
- 声明和赋值不能分开;
//数组: /*let arr=[1,2,3]; let a=arr[0]; let b=arr[1]; let c=arr[2];*/ //可以写成这样 let [a,b,c] = [1,2,3] console.log(a,b,c); //1,2,3 //-------------------------------------------------------------------------------------- //json let {a,b,c} = {a:1,b:2,c:4} console.log(a,b,c); //1,2,3
4.数组扩展
添加了四个方法:map reduce filter forEach
(1)map — 映射 — 一个对一个
let arr=[10,2,3]; let result=arr.map(function(item){ //alert(item) return (item*2) }) alert(result) // 20,4,6 //可以写成箭头函数 let arr=[10,2,3]; let result=arr.map(item=>item*2); alert(result) // 20,4,6
--------------------------------------------------------------------------------------
//在写一个应用
let score=[90,40,58,60];
let result=score.map(item=>item>=60?"及格":"不及格");
alert(result) //及格,不及格,不及格,及格
(2)reduce — 汇总 — 一堆出来一个
// 总和 var arr=[88,12,20]; let result=arr.reduce(function(tmp,item,index){ //alert(tmp+','+item+","+index) 三个参数分别代表:中间结果、每次的数、下标 return tmp+item; }) alert(result) // 120 //求平均数 let result =arr.reduce(function(tmp,item,index){ if(index!=arr.length-1) //不是最后一次 { return tmp+item; //先求和 } else { return (tmp+item)/arr.length; //去求平均数 } }) alert(result) // 40
(3)filter — 过滤器
//求能被三整除的 let arr=[88,12,20,11]; let result=arr.filter(item=>item%3==0) alert(result) //12
(4)forEach — 循环(迭代)
let arr=[12,10,44]; arr.forEach((item,index)=> { alert(index+":"+item) });
// 0:12
// 1:10
// 2:44
5.字符串扩展
- 添加了两个新方法 :startsWith 起始,endsWith 结尾
//startsWith
let str="http://www.baidu.com"; if(str.startsWith("http://")){ alert("普通网址") } else if(str.startsWith("https://")) { alert("保密网址") } else { alert("其他网址") } //普通网址//endsWith let str="xxx.png"; if(str.endsWith("txt")) { alert("文本文件"); } else if(str.endsWith("png")) { alert("图片文件"); } else { alert("其他"); } //图片文件
- 字符串模板:字符串连接
1.可以把东西塞到字符串里 ${ }
2.可以换行let title="标题"; let content="内容"; let str=`<div> <h1>${title}</h1> <p>${content}</p> </div>`; alert(str); //结果: <div> <h1>标题</h1> <p>内容</p> </div>
6.面向对象
之前的缺点:构造函数和类不区分
主要变化:1.class关键字,构造器(constructor) 和类分开了;
2.class 里直接加方法。
//之前的 function User(name,pass) { this.name=name; this.pass=pass; }; User.prototype.showName=function(){ alert(this.name); }; User.prototype.showPass=function(){ alert(this.pass); }; var Obj=new User("wy","123"); Obj.showName(); Obj.showPass(); // 结果 wy 123 //ES6 class User{ constructor(name,pass){ //constructor 构造器 this.name=name; this.pass=pass; } showName(){ alert(this.name) } showPass(){ alert(this.pass) } } var Obj=new User("wy","123"); Obj.showName(); Obj.showPass(); // 结果 wy 123
继承:
extends:扩展,延展
super:超类,父类
// 之前的继承写法 function User(name,pass) { this.name=name; this.pass=pass; } User.prototype.ShowName=function(){ alert(this.name); } User.prototype.ShowPass=function(){ alert(this.pass); } function VipUser(name,pass,level) { User.call(this,name,pass); this.level=level; } VipUser.prototype=new User(); VipUser.prototype.constructor=VipUser; //会改变constructor指向,需要手动恢复 /*for(var i in User.prototype) { VipUser.prototype[i]=User.prototype[i]; }*/ VipUser.prototype.ShowLevel=function(){ alert(this.level) } var obj=new VipUser("wy","123","3"); obj.ShowName(); obj.ShowPass(); obj.ShowLevel(); // wy // 123 // 3 //--------------------------------------------------------------------------------------------------------------- //ES6 class User{ constructor(name,pass){ this.name=name; this.pass=pass; } showName(){ alert(this.name) } showPass(){ alert(this.pass) } } class VipUser extends User{ //用extends constructor(name,pass,level){ super(name,pass); //用 super 从父类上继承属性 this.level=level; } showlevel(){ alert(this.level); } } var Obj=new VipUser("wy","123","3"); Obj.showName(); Obj.showPass(); Obj.showlevel(); // wy // 123 //3
7.json扩展
- 1. json 对象 新加了两个方法
(1). json.stringify : 把json 变成字符串的方法。
var json={a:12,b:11}; var str='https://www.baidu.com/path/user? data='+encodeURIComponent(JSON.stringify(json)); //字符串 alert(str)
(2). json.parse : 把字符串变成json。
var str='{"a":12,"b":11,"c":"abc"}'; var json=JSON.parse(str); console.log(json)
- 2. json 简写
(1)名字一样:名字和值(key和value)一样的 ,留一个就行;
let a=12; let b=12; //var json={"a":a,"b":b,"c":"abc"}; var json={a,b,c:"abc"}; //简写 console.log(json)
var json={ "a":12, /*show:function(){ alert(this.a) }*/ show(){ //简写 alert(this.a) } } json.show();
8.promise对象 - 消除异步操作
官方上说是 异步编程的一种解决方案。
有了Promise
对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。
Promise
也有一些缺点:
首先,无法取消Promise
,一旦新建它就会立即执行,无法中途取消。
其次,如果不设置回调函数,Promise
内部抛出的错误,不会反应到外部。
第三,当处于Pending
状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
基本用法:
let p=new Promise(function(resolve,reject){ //Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve
和reject
。它们是两个函数 //异步代码 //resolve --成功了 //reject -- 失败了 //alert(resolve) $.ajax({ url:'data/arr1.txt', dataType:'json', success(arr){ resolve(arr) }, error(err){ reject(err); } }) }); p.then(function(arr){ //then
方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为Resolved时调用,第二个回调函数是Promise对象的状态变为Reject时调用。 alert("成功"+arr); console.log(arr) },function(err){ console.log(err) alert("失败"+err); }); ------------------------------------------------------------------------------------------------------------------------------------------------------------ //封装起来 就是 function CreatPromise(url){ //返回出去 return new Promise(function(resolve,reject){ $.ajax({ url, dataType:'json', success(arr){ resolve(arr) }, error(err){ reject(err); } }) }); } //Promise.all
方法用于将多个Promise实例,包装成一个新的Promise实例。 Promise.all([ //Promise.all
方法接受一个数组作为参数 CreatPromise('data/arr.txt'), CreatPromise('data/json.txt'), ]).then(function(arr){ let [arr1,arr2]=arr; console.log(arr1); console.log(arr2); //alert(arr1); //alert(arr2); alert("全成功"); },function(err){ console.log(err); alert("至少有一个失败"); })
有了jquery 的promise (jquery 已经封装好了promise):
Promise.all([ $.ajax({url:'data/arr.txt',dataType:"json"}), $.ajax({url:'data/json.txt',dataType:"json"}) ]).then(result=>{ let [arr,json]=result; alert("成功"); console.log(arr,json); },err=>{ alert("失败"); })
9.generator函数
也是一种异步编程解决方案。
普通函数--一路到底(飞机、高铁);涉及到异步操作只能用回调的方式。
generator函数--中间能停(出租车); 可以停,数据什么时候回来在走,适合逻辑性强的。注意不能写成箭头函数。
promise--也是不是停;有逻辑的情况下很麻烦,适合一次读一堆数据。
第一个generator 函数实例:
//generator函数 function *show(){ //多一个星号 可以单独放,可以贴function或者函数名 alert("a"); yield; //配合generator函数使用 暂时放弃执行 alert("b"); } let genObj=show(); //创建一个generator对象(和普通函数不一样,普通函数直接调用即可) alert(genObj); //Object generator console.log(genObj);
//next方法 指向下一个状态
genObj.next(); //a
genObj.next(); //b
调用遍历器对象的next方法,使得指针移向下一个状态。
也就是说,每次调用next
方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield
语句(或return
语句)为止。
换言之,Generator函数是分段执行的,yield
语句是暂停执行的标记,而next
方法可以恢复执行。
generator 原理:
//generator函数 function *show(){ alert("a"); yield; alert("b"); } //!generator原理是,把大函数切成多个小函数 function show_1(){ alert("a"); } function show_2(){ alert("b"); } let genObj=show(); genObj.next(); //show_1 genObj.next(); //show_2
yield 是什么?
(1)可以传参
//generator函数 function *show(){ alert("a"); let c=yield; alert("b"); alert(c); // ——>5 } let genObj=show(); //给yield 传参 第一个是没用的,接收的是第二个参数 genObj.next(12); genObj.next(5);
//5
(2)可以返回
//generator函数 function *show(){ alert("a"); yield 12; alert("b"); return 2;// 最后一步的过程通过return给 } let genObj=show(); let res1=genObj.next(); //有中间结果的 console.log(res1); // ->{value: 12, done: false} let res2=genObj.next(); //有中间结果的 //console.log(res2); // 没有return时->{value: undefined, done: true} console.log(res2); // 有return时->{value: 2, done: true}
yield语句
由于Generator函数返回的遍历器对象,只有调用next
方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield
语句就是暂停标志。
遍历器对象的next
方法的运行逻辑如下。
(1)遇到yield
语句,就暂停执行后面的操作,并将紧跟在yield
后面的那个表达式的值,作为返回的对象的value
属性值。
(2)下一次调用next
方法时,再继续往下执行,直到遇到下一个yield
语句。
(3)如果没有再遇到新的yield
语句,就一直运行到函数结束,直到return
语句为止,并将return
语句后面的表达式的值,作为返回的对象的value
属性值。
(4)如果该函数没有return
语句,则返回的对象的value
属性值为undefined
。
需要注意的是,yield
语句后面的表达式,只有当调用next
方法、内部指针指向该语句时才会执行,因此等于为JavaScript提供了手动的“惰性求值”(Lazy Evaluation)的语法功能。
generator 应用
generatro 搭配 runner 写更加简化。
runner.js :
function runner(_gen){ return new Promise((resolve, reject)=>{ var gen=_gen(); _next(); function _next(_last_res){ var res=gen.next(_last_res); if(!res.done){ var obj=res.value; if(obj.then){ obj.then((res)=>{ _next(res); }, (err)=>{ reject(err); }); }else if(typeof obj=='function'){ if(obj.constructor.toString().startsWith('function GeneratorFunction()')){ runner(obj).then(res=>_next(res), reject); }else{ _next(obj()); } }else{ _next(obj); } }else{ resolve(res.value); } } }); }
generator :
runner (function *(){ let data1=yield $.ajax({url:"data/1.txt",dataType:"json"}); let data2=yield $.ajax({url:"data/2.txt",dataType:"json"}); let data3=yield $.ajax({url:"data/3.txt",dataType:"json"}); console.log(data1,data2,data3); })
总结:
2015年6月正式发布的ECMAScript 6.0(简称 ES6)是 JavaScript 语言的下一代标准,它越来越向后台化发展。
兼容:IE10+、chrome、FireFox、移动端、NodeJs。
要兼容:(1)提前编译
(2)在线转换 :引一个browser.js <scirpt type="text/babel">