ECMAScript6(ES6)標準之函式擴充套件特性箭頭函式、Rest引數及展開操作符
ES6擴充套件了很多語法糖語法
其中對於函式我們又可以使用一種叫做“箭頭函式”的寫法
同時引入了Rest引數
利用“…”可以獲取多餘引數
這樣就我們就不要使用arguments物件了
下面我來詳細地談一談
函式預設引數
ES6沒有出現之前
面對預設引數會讓很多人感到痛苦
大家會採用各種hack
比如:arr = arr || []
現在要容易得多
function foo(name = 'payen'){
console.log('my name is ' + name);
}
foo(); //my name is payen
只需要在引數列表中像賦值一樣
就可以使用預設引數
Rest引數
當一個函式的最後一個引數有“…”這樣的字首
它就會變成一個引數的陣列
為了讓大家更好的理解
先來回憶一下我們以前ES6之前使用的arguments
function foo(){
var args = Array.prototype.slice.call(arguments);
console.log(args);
}
foo(1, 2, 3);// [1, 2, 3]
這裡我先使用Array原型上的slice把arguments類陣列
變成了真正的陣列
然後列印這個引數陣列
現在我們使用ES6的Rest引數
程式碼可已修改為這樣
function foo(...args){
console.log(args);
}
foo(1, 2, 3);// [1, 2, 3]
確實要簡潔很多
注意Rest引數與arguments有以下幾點區別
- Rest引數是未指定變數名的引數陣列
arguments是全部引數的集合 - Rest引數是真正的陣列
arguments物件只是有length屬性的類陣列
展開操作符
上面我們提到了“…”操作符
包括我之前寫到的解構賦值語法
都用到了它
它是ES6的新特性
然而它的強大不只如此
“…”叫做展開操作符
允許一個表示式在某處展開,用於
存在多個引數(函式呼叫)、多個元素(陣列)、多個變數(解構賦值)
下面我就把除了Rest引數以外的用法總結一下
(解構賦值的應用也不談了,忘了的同學戳這裡:
函式呼叫
想一想我們在ES6之前
如何將陣列拆分作為引數傳入函式
var arr = [1, 2, 3];
function demo(x, y, z){
console.log(x, y, z);
}
demo.apply(null, arr);// 1 2 3
利用apply來達到目的
看起來怪怪的
而現在我們可以這樣做
let arr = [1, 2, 3];
function demo(x, y, z){
console.log(x, y, z);
}
demo(...arr);// 1 2 3 《--
陣列字面量
ES6之前我們想要拼接陣列
可以使用concat()
var arr1 = [1, 2, 3];
var arr2 = [4, 5, 6];
var arr = arr1.concat(arr2);
console.log(arr);// [1, 2, 3, 4, 5, 6]
利用展開操作符就不需要呼叫這個方法了
var arr1 = [1, 2, 3];
var arr2 = [4, 5, 6];
var arr = [...arr1, ...arr2];
console.log(arr);// [1, 2, 3, 4, 5, 6]
展開物件
展開陣列是如此簡單易用
那麼物件呢?
let person = {
name: 'payen',
sex: 'male',
};
person = {...person, age: 19};
console.log(person);
把這段程式碼放在你的編輯器了
你會發現它根本不能執行
因為ES6根本沒有這樣的語法
不過它是ES7的提案之一
可以讓我們以更加簡潔的形式
將一個物件的可列舉屬性複製到另一物件上
(ps:這一特性可以通過Babel及其外掛實現)
(ps:React在JSX語法已經採用這種寫法)
箭頭函式
箭頭函式是一種更簡單的函式宣告方式
它永遠是匿名函式
我們一般的函式寫法
var sum = function(a, b){
return a + b;
};
箭頭函式
let sum = (a, b) => {
return a + b;
};
當“箭頭”後面是表示式的時候
還可以簡化(省略“{ }”大括號 和 return關鍵字)
let sum = (a, b) => a + b;
略去function關鍵字
“=>”的前面是“( )”和內部的引數列表
“=>”的後面是程式碼塊
這個胖胖的箭頭被人為 單調乏味冗長 的function關鍵字的簡寫
(不過我覺得現在所有英文單詞中function這個詞我敲得最快(+﹏+)~)
不過它的作用可不僅僅是略微提高一點我們鍵盤的壽命
這個一會兒再說
回撥函式
先來看看它在回撥函式中應用它
var arr = [1, 2, 3];
console.log(arr.map((value)=>value*2));// [2, 4, 6]
不知道大家能不能看懂
它就相當於下面的程式碼
var arr = [1, 2, 3];
console.log(arr.map(function(value){
return value*2;
}));// [2, 4, 6]
返回物件
還有一點要注意
就是如果我們的函式只是返回一個物件
var foo = function(){
return {
name: 'payen'
}
}
使用箭頭函式簡化一步
let foo = () => {
return {
name: 'payen'
}
}
再簡化一步
let foo = () => {name: 'payen'}; //錯誤的寫法
這時我的編輯器提示語法問題了
這是應為它認為“=>”後面是一個程式碼塊
而不會理解為是要返回的物件
解決辦法仍然是使用萬能的“( )”
這樣編輯器、瀏覽器都會認為它是表示式了
let foo = () => ({name: 'payen'}); //正確的寫法
this指向
巢狀函式就會產生this指向的問題
舉個例子
var flag = 'global';
var obj = {
flag: 'object',
method: function(){
console.log(this.flag);
setTimeout(function(){
console.log(this.flag);
}, 200)
}
};
obj.method();//object global
即便把var宣告全改為let也會輸出 object undefined
第一個console.log不用說
物件的巢狀函式會指向全域性window物件
method方法丟失了同this之間的繫結
這被認為是JavaScript在設計上的重大缺陷
我們一般都會採用一些hack來解決
使用臨時快取變數
藉助於詞法作用域
利用一個識別符號self(通常起名self、that、_this)
(ES3)
var flag = 'global';
var obj = {
flag: 'object',
method: function(){
var self = this;
setTimeout(function(){
console.log(self.flag);
}, 200)
}
};
obj.method(); //object
或者利用bind()
(ES5)
//ES5
var flag = 'global';
var obj = {
flag: 'object',
method: function(){
setTimeout(function(){
console.log(this.flag);
}.bind(this), 200)
}
};
obj.method(); //object
現在使用箭頭函式可以輕鬆解決問題
(ES6)
var flag = 'global';
var obj = {
flag: 'object',
method: function(){
setTimeout(()=>console.log(this.flag), 200);
}
};
obj.method(); //object
我們看到
箭頭函式在涉及this繫結時的行為
與普通函式行為完全不同
它是用當前的此法作用域覆蓋this本來的值
(“繼承”了method()方法的this繫結)
最後還是要向大家強調一下箭頭函式不夠理想的一點
它是匿名而不是具名的