es各個版本的兼容性 http://kangax.github.io/compat-table
es6(ES2015)在IE10+、chorme、firefox、移動端和NodeJs都能得到有效支持。
對於不支持es6的情況,有兩種方式處理:
(1)在線轉換
//使用babel babel也叫browser.js 注意指定script的type="text/bable"
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>es6在線轉換</title>
<script src="browser.js" charset="utf-8"></script>
<script type="text/babel">
let a=1;
let b=2;
alert(a+b);
</script>
</head>
<body>
</body>
</html>
(2)提前編譯【推薦】
//安裝babel 在這之前你應該安裝好node.js,因爲npm是隨同NodeJS一起安裝的包管理工具
npm i babel-cli -g
//使用babel命令進行編譯 在這之前你也需要對babel進行配置
babel es6.js -o compiled.js
1、let聲明
es5變量聲明方式var存在兩個問題:①變量提升,即變量不需要先聲明後使用,亦可先使用後聲明。②變量的作用域只有兩種:全局作用域和局部作用域。
let聲明的變量作用域爲塊級作用域,且必須先聲明後使用,使代碼更加嚴謹。
看下面這題,輸出結果應爲多少?
var a = 10;
(function(){
console.log(a);
var a = 100;
})();
答案是undefined,因爲var聲明變量的提升效果,這裏相當於:
var a = 10;
(function(){
var a;
console.log(a);
a = 100;
})();
另外,值得注意的是,JavaScript永遠是先解析聲明函數,再解析變量。
var a = 1;
function a(x){
return 2*x;
}
console.log(a); //1
此時,還有一種情況需要注意:
var a;
function a(x){
return 2*x;
}
console.log(a); //function a
這裏是由於a沒有被賦值,還是指向回原來的function a();
下面列出一個在學習中仍未解決的問題:
var a=1;
function foo(){
if(false){
var a=2;
}
console.log(a);
}
foo();
//執行結果:undefined
2、const聲明
定義後必須賦值,且賦值後不可改變。
①賦常量
②賦變量
③賦數組
④賦對象
由上面的結果可知,對const賦予常量和變量不能改變其值。但是對const賦予數組和對象,只需要更改數組或對象的值,const裏的值也發生了改變,說明對於const對於數組和對象不變的是引用。
注意:let / const不能重複聲明 ,var在非嚴格模式下能夠重複聲明
3、箭頭函數(作爲了解函數的一種新的寫法)
function show(){
/*es5函數寫法*/
}
let show = ()=>{
/*箭頭函數寫法*/
}
(1)如果只有一個參數,()可以省略
(2)如果只有一個return,{}可以省略
function show(a){
return a*2; //es5寫法
}
//es6箭頭函數()和{}省略,這裏的參數和return個數必須只能是一個,多也不行少也不行
let show = a => a*2;
4、變量的解構賦值(數組法)
var [a,b,c]=[1,2,3];
//相當於 var a=1,b=2,c=3;
var [a,[b,c]]=[1,[2,3]];
//相當於 var a=1,b=2,c=3;
var [a,b='default',c='default']=[1,2];
//a=1,b=2,c='default'
var [a,b,c]=[1,2];
//a=1,b=2,c=undefined
var [a,...c]=[1,2,3];
//a=1,c=[2,3]
5、變量的解構賦值(對象法)
var obj = {a:1,b:2};
var {a,b}=obj; //相當於var a=1,b=2;
var obj = {a:1,b:2};
var {a:A,b}=obj;
//a被替換成A,相當於var A=1,b=2;
//亦可設置默認值
var obj = {a:1};
var {a:A=3,b=4}=obj; //A=1,b=4
var a,b;
var obj = {a:1,b:2};
({a,b}=obj);
//注意這裏要加上括號,因爲若不加上括號,js解析器會認爲“{”後面是代碼塊
複雜點的解構賦值:
var obj = {
arr:['Yo',{a:1}]
}
var {arr:[greet,{a}]}=obj;
//greet='Yo',a=1
//結構對上就可以了
注意:(1)左右兩邊結構相同纔能有效賦值(2)聲明賦值不能分開
let [a,b,c];
[a,b,c] = [12,5,8];
//這種寫法會報錯
//Uncaught SyntaxError: Missing initializer in destructuring declaration
6、解構賦值的一些其他用法(字符串,傳參)
①讀取字符串長度
let {length}="hello"; //變量length=5 {}裏面必須是length
②字符串賦值
let [a,b,c]="ion";
//a='i', b='o', c='n'
③函數傳參解構
var arr=[1,2];
function test([a,b]){
console.log(a+" "+b);
}
test(arr); //1 2
var obj={b:2};
function test({b,a=10}){
console.log(a+" "+b);
}
test(obj); //10 2
7、新增字符串方法
includes() startsWith() endsWith() repeat()
console.log('You'.indexOf('Y') !== -1);//原來判斷字符串是否包含Y的方法 true
console.log('You'.includes('Y'));
//es6判斷字符串是否包含Y true
console.log('You'.startsWith('Y'));//是否以Y開始 true
console.log('You'.endsWith('u'));//是否以u開始 true
console.log('You'.repeat('3'));//重複字符3次 YouYouYou
8、模板字符串
let title='hello world!';
let tpl1='<div>'+'<span>'+title+'</span>'+'</div>';
let tpl2=`
<div>
<span>${title}</span>
</div>
`;
console.log("tpl1",tpl1);
console.log("tpl2",tpl2);
打印結果如下:
es6${}裏面還能內嵌反斜號添加其他變量,如下:
let tpl2=`
<div>
<span>${title + `<span>${1234}</span>`}</span>
</div>
`;
9、數組(這裏的函數可以看成對數組每一項進行循環的操作)
map 映射 一 一對應 如把分數數組映射成及格情況數組
let score = [12,53,89,65,49,99,56];
//注意下面用了箭頭函數的寫法 注意參數只能有一個,這裏我們命名爲item
//每次return把結果傳給接收變量
let result = score.map(item => item>=60?"及格":"不及格");
console.log(result);
//["不及格", "不及格", "及格", "及格", "不及格", "及格", "不及格"]
reduce 彙總 一堆出來一個 如求和、算平均數
let array = [12,53,89,65,49,99,56];
//第一個參數temp是上次循環返回值
//第二個參數item是數組的當前項,第一次是12,第二次是53 。。。。。
//第三個參數是指針,從1開始
//每次return把結果傳入下次形參,直到遍歷到最後一個數
let result = array.reduce(function(temp,item,index){
return temp+item;
});
alert(result);
filter 過濾器 只顯示符合條件的值
let score = [12,53,89,65,49,99,56];
//item爲數組的當前項,返回true則顯示,false則不顯示,最後返回顯示的數組
let result = score.filter(function(item){
if(item<60){
return false;
}else{
return true;
}
});
alert(result); //89,65,99
//------------------上面的代碼可用箭頭函數簡寫爲-----------------
let score = [12,53,89,65,49,99,56];
let result = score.filter(item=>item>=60);
alert(result); //89,65,99
forEeach 循環(迭代)
let array = [12,53,89,65,49,99,56];
//第一個參數是數組當前項,第二個參數是索引
array.forEach((item,index)=>{
alert(index+","+item);
});
9、Symbol數據類型
ES5 的對象屬性名都是字符串,這容易造成屬性名的衝突。比如,你使用了一個他人提供的對象,但又想爲這個對象添加新的方法(mixin 模式),新方法的名字就有可能與現有方法產生衝突。如果有一種機制,保證每個屬性的名字都是獨一無二的就好了,這樣就從根本上防止屬性名的衝突。這就是 ES6 引入Symbol
的原因。
對變量或值調用 typeof 運算符將返回下列值之一:
- undefined - 如果變量是 Undefined 類型的
- boolean - 如果變量是 Boolean 類型的
- number - 如果變量是 Number 類型的
- string - 如果變量是 String 類型的
- object - 如果變量是一個對象或 Null或者數組
- function -如果變量是個函數名
- symbol -es6引入的數據類型
注意不要和JavaScript基本數據類型搞混,基本數據類型有7個:undefined、null、Boolean、String、Number、Object、Symbol (根據阮一峯老師的教程,基本數據類型就這7種,不包括Array)
①每次創建Symbol,它的值都不一樣
let a = Symbol();
let b = Symbol();
console.log(a === b); //false
②Symbol裏面可以傳入一個參數,用於描述你創建的Symbol,傳入參數對他的值沒有影響
let a=Symbol('this is a Symbol');
③應用:在不同的塊中,臨時重寫變量
let name =Symbol();
{
var person = {};
person[name] ='file1';
console.log('person[name]',person[name]); //file1
}
{
let name = Symbol();
person[name] = 'file2';
console.log('person[name]',person[name]); //file2
}
console.log('person[name]',person[name]); //file1
④Symbol 值不能與其他類型的值進行運算,會報錯。
let sym = Symbol('My symbol');
"your symbol is " + sym // TypeError: can't convert symbol to string
`your symbol is ${sym}` // TypeError: can't convert symbol to string
⑤Symbol 值作爲對象屬性名時,不能用點運算符
const mySymbol = Symbol();
const a = {};
a.mySymbol = 'Hello!';
a[mySymbol] // undefined
a['mySymbol'] // "Hello!"
10、Proxy
var user = new Proxy({},{
get:function(obj,prop){
if(prop == 'full_name')
return obj.fname + ' ' +obj.lname;
}})
user.fname='Bob';
user.lname = 'Wood';
console.log("user.full_name: ",user.full_name); //user.full_name:Bob Wood
console.log("user.age: ",user.age); //undefined
11、Set
Set裏面數組值唯一,不重複
var s = new Set([1,2,3,3]);
console.log('s.size', s.size); //3
console.log('s', s); // {1,2,3}
s.add(4); //添加4
console.log('s', s); //{1,2,3,4}
s.delete(2); //刪除2
console.log('s', s); //{1,3,4}
console.log('s.has(5)',s.has(5)); //false 判斷Set是否包含5
s.clear(); //清空Set
console.log('s', s) //{}
12、面向對象
es6之前寫法:
//爲了區分函數和類,在es5中類首字母大寫 User是這裏是構造函數
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 u1 = new User('ion','123456');
u1.showName();
u1.showPass();
es6寫法:
//這裏的constructor就相當於構造器,定義方法不需要指定function,函數之間不需要符號(如逗號)分隔
class User{
constructor(name,pass){
this.name = name;
this.pass = pass;
}
showName(){
alert(this.name);
}
showPass(){
alert(this.pass);
}
}
var u1 = new User('ion','123456');
u1.showName();
u1.showPass();
13、繼承
es6之前寫法:
function User(name,pass){
this.name = name;
this.pass = pass;
}
User.prototype.showName = functi
alert(this.name);
}
User.prototype.showPass = functi
alert(this.pass);
}
function VipUser(name,pass,level
User.call(this,name,pass);
this.level = level;
}
VipUser.prototype = new User();
VipUser.prototype.constructor =
VipUser.prototype.showLevel = fu
alert(this.level);
}
var u2 = new VipUser('ion','1234
u2.showName();
u2.showPass();
u2.showLevel();
es6寫法:
class User{
constructor(name,pass){
this.name = name;
this.pass = pass;
}
showName(){
alert(this.name);
}
showPass(){
alert(this.pass);
}
}
//extends 指定繼承自who 這裏的extends和super(超類)與Java比較類似
class VipUser extends User{
constructor(name,pass,level){
//繼承父類的構造函數與方法
super(name,pass);
this.level = level;
}
showLevel(){
alert(this.level);
}
}
var u1 = new VipUser('ion','123456',3);
u1.showName();
u1.showPass();
u1.showLevel();
14、JSON
json對象與json字符串互換:
//json對象轉字符串方法 JSON.stringify();
//json字符串轉json對象方法 JSON.parse();
let json = {a:5,b:4};
let str_json = JSON.stringify(json);
let obj_json = JSON.parse(str_json);
console.log(str_json); //輸出爲{"a":5,"b":4},即str_json = '{"a":5,"b":4}';
console.log(typeof(str_json)); //string
console.log(obj_json); //{a:5,b:4}
console.log(typeof(obj_json)); //object
注意:js字符串要解析成json對象要符合一定的標準。
(1){}裏面只能用雙引號
(2)key必須使用雙引號包裹
let tjson = '{"a":"abc","b":2,"c":3}'; 正確
let fjson1 = '{a:"abc",b:2,c:3}'; 錯誤,key沒有用雙引號包裹
let fjson2 = "{'a':'abc','b':2,'c':3}"; 錯誤,json字符串裏面只能用雙引號
另外,es6中,json的key和value一樣的時候,可以省略只寫一個。json裏面的方法可以直接去掉冒號和function
let a=12;
//es6之前寫法
let json = {
a : a,
show : function(){
alert(this.a);
}
}
//es6寫法
let newJson = {
a,
show(){
alert(this.a);
}
}
15、Promise
在JavaScript的世界中,所有代碼都是單線程執行的。由於這個“缺陷”,導致JavaScript的所有網絡操作,瀏覽器事件,都必須是異步執行。異步執行可以用回調函數實現:
<script src="jquery.js"></script>
<script>
$.ajax({
url : "data/userInf.txt",
dataType : "json",
type : "POST",
async : true,
success : function(data){
//do something
},
error : function(erroThrow){
console.log(erroThrow);
}
});
</script>
這種把回調函數寫在ajax的操作不僅不太好看,同時也不便於代碼的複用。
古人云:“君子一諾千金”,這種“承諾將來會執行”的對象在JavaScript中稱爲Promise對象。Promise對象的主要作用就是消除異步操作,用同步一樣的方式來說書寫異步代碼。
let p = new Promise(function(resolve,reject){
//這裏的resolve和reject都是函數
//resolve 成功了
//reject 失敗了
$.ajax({
url : "data.txt",
dataType : "json",
success : function(data){
resolve(data);
},
error : function(errorThrow){
reject(errorThrow);
}
});
});
/*then()的第一個函數就相當於resolve,第二個函數就相當於reject。參數與上面的resolve和reject內的參數一致*/
p.then(function(data){
alert("成功了"+data);
},function(errorThrow){
alert("失敗了");
console.log(errorThrow);
});
//ajax操作不能用file開頭的地址打開,需要使用localhost,即在服務器上運行代碼,否則會出現跨域問題
上面的Promise對象就成功的把回調函數與異步邏輯給區分了開來。
Promise有兩個方法all()和race(),分別用於並行的ajax操作和容錯式的ajax操作。
let p1 = new Promise(function(resolve,reject){
$.ajax({
url : "data.txt",
dataType : "json",
success : function(data){
resolve(data);
},
error : function(errorThrow){
reject(errorThrow);
}
});
});
let p2 = new Promise(function(resolve,reject){
$.ajax({
url : "data2.txt",
dataType : "json",
success : function(data){
resolve(data);
},
error : function(errorThrow){
reject(errorThrow);
}
});
});
//all()方法必須所有的異步請求成功纔會執行resolve
//注意all()裏面的參數是Promise對象數組,then()的第一個和第二個函數參數是resolve函數和reject函數的參數數組
Promise.all([p1,p2]).then(function(array){
let [res1,res2] = array;
alert("全都成功了");
console.log(res1);
console.log(res2);
},function(){
alert("至少一個失敗了");
});
當然,對於上面這種all()方法的情況,把創建Promise對象的操作封裝成一個函數會顯得代碼簡潔很多,這裏這樣寫感覺會比較好理解。封裝成函數的代碼如下:
function createPromise(url){
return new Promise(function(resolve,reject){
$.ajax({
url : url,
dataType : "json",
success : function(data){
resolve(data);
},
error : function(errorThrow){
reject(errorThrow);
}
});
});
}
Promise.all([
createPromise("data.txt"),
createPromise("data2.txt")
]).then(function(array){
let [res1,res2] = array;
alert("全都成功了");
console.log(res1);
console.log(res2);
},function(){
alert("至少一個失敗了");
});
Promise.race()方法用法如下:
function createPromise(url){
return new Promise(function(resolve,reject){
$.ajax({
url : url,
dataType : "json",
success : function(data){
resolve(data);
},
error : function(errorThrow){
reject(errorThrow);
}
});
});
}
/*有些時候,多個異步任務是爲了容錯。比如,同時向兩個URL讀取用戶的個人信息,只需要獲得先返回的結果即可。其
餘結果拋棄*/
Promise.race([
createPromise("data.txt"),
createPromise("data2.txt")
]).then(function(array){
let res1 = array;
alert("至少一個成功了");
console.log(res1);
},function(){
alert("全部失敗了");
在jquery的較新版本中也有對Promise對象的封裝,使用jquery3.2以上的版本,則可以使寫Promise對象的代碼更加簡潔。
//jquery3.2以上版本$.ajax方法返回值就是一個Promise對象
Promise.race([
$.ajax({url:'data.txt',dataType:'json'}),
$.ajax({url:'data2.txt',dataType:'json'}),
]).then(function(array){
let res1 = array;
alert("至少一個成功了");
console.log(res1);
},function(){
alert("全部失敗了");
16、generator函數(生成器函數)
最大特點:中間可以通過yield暫停
//這裏的“*”代表這是一個generator函數,*號可以靠function放,可以靠show放,也可以放在兩者中間各帶空格
//就是不可以這樣:function*show(){}
function *show(){
alert("a");
yield;
alert("b");
yield;
alert("c");
}
//generator函數是踹一腳走一步,和普通函數一條路走到底不同
//generator函數不能直接執行,利用其返回的generator對象的next()方法控制走到哪一步
let genObj = show();
genObj.next(); //alert("a")
genObj.next(); //alert("b")
genObj.next(); //alert("c")
(1)通過next()給yield傳值
function *show(a){
alert("a"+a); //a1
let b = yield;
alert("b"+b); //b3
let c = yield;
alert("c"+c); //b4
}
//開始沒有yield,可以通過函數show傳參來傳值
let genObj = show(1);
//如果沒有第一個next(),什麼都不會輸出.
genObj.next(2);
/*從輸出可以看出,給第一個next()傳參是沒有意義的,在執行時可以猜測這一步是進入函數的意思,並沒有遇到yield來傳值*/
genObj.next(3);
genObj.next(4);
(2)yield給next()傳值
function *show(){
alert("a");
yield 1;
alert("b");
yield 2;
alert("c");
//最後沒有yield,可以通過return返回值給next()
return 3;
}
let genObj = show();
let res1 = genObj.next();
let res2 = genObj.next();
let res3 = genObj.next();
console.log(res1); //{done:false,value:1}
console.log(res2); //{done:false,value:2}
console.log(res3); //{done:true,value:3}
//done即指是否執行到最後一步