JavaScript 參數(shù)中的數(shù)組展開 [譯]
譯者注:本文要講的是ECMAScript 6中的知識點,如果你連ES5都不了解的話.我得說,你已經(jīng)很落后了.CSS4,HTML6,甚至ES7 ES8都已經(jīng)開始規(guī)劃了,趕緊形動起來吧,否則淘汰!
有些時候,我們需要把一個數(shù)組展開成多個元素,然后把這些元素作為函數(shù)調(diào)用的參數(shù).JavaScript中可以使用Function.prototype.apply來實現(xiàn)這種展開操作,但它不能被應用在執(zhí)行構造函數(shù)的情況下.本文解釋了什么是展開操作以及如何在使用new運算符的同時進行展開操作.
1.展開(Spreading)
展開的意思是在一個函數(shù)調(diào)用或方法調(diào)用中,或者執(zhí)行一個構造函數(shù)時,通過一個數(shù)組來提供所需的參數(shù).在Python中,這種操作稱之為unpacking. ECMAScript.next中已經(jīng)有了(展開操作符)spread operator (表示為一個前綴...)來執(zhí)行這個展開操作.在目前的JavaScript中,你可以通過Function.prototype.apply方法來實現(xiàn)同樣的效果.
譯者注:展開操作符除了能用在實參的位置,把數(shù)組展開,還可以用在形參的位置,表示剩余參數(shù).請看我翻譯的MDN文檔剩余參數(shù)
2.展開函數(shù)參數(shù)
Math.max()方法返回它的0到若干個數(shù)值類型的參數(shù)中的最大值.有了展開操作符,你可以直接使用一個數(shù)組來作為參數(shù):
Math.max(...[13, 7, 30])
這等同于下面的寫法
Math.max(13, 7, 30)
在目前的JavaScript中,你可以使用apply().
> Math.max.apply(null, [13, 7, 30])
30
apply方法的作用是:使用下面的這種調(diào)用方式:
func.apply(thisValue, [param1, param2, ...])
來代替這種
thisValue.func(param1, param2, ...)
需要注意的是,func不一定是屬于thisValue的方法,apply可以讓它臨時擁有這個方法.
3.展開構造函數(shù)的參數(shù)
Date構造函數(shù)接受幾個數(shù)值類型的參數(shù),產(chǎn)生一個Date對象.通過展開操作符,你可以直接傳入一個數(shù)組.
new Date(...[2011, 11, 24]) // 2011年的圣誕夜
但是,這次我們不能使用apply方法來實現(xiàn)展開操作,因為它不能與new一起工作:
> new Date.apply(null, [2011, 11, 24])
TypeError: function apply() { [native code] } is not a constructor
new運算符希望Date.apply是一個構造函數(shù).就算你用小括號將這個表達式括起來,根本問題還是存在:apply執(zhí)行的是一個函數(shù)調(diào)用,它不能將參數(shù)傳遞給new運算符.
3.1 解決辦法
第一步. 我們先讓結果變的正確,稍候再考慮怎么用數(shù)組代替分割開的參數(shù).
new (Date.bind(null, 2011, 11, 24))
我們先用bind()來創(chuàng)建一個無參數(shù)的函數(shù)(參數(shù)已經(jīng)綁定在這個綁定函數(shù)的內(nèi)部了),然后使用new調(diào)用它,就像調(diào)用一個普通的構造函數(shù)一樣.bind的函數(shù)簽名如下:
func.bind(thisValue, arg1, arg2, ...)
bind函數(shù)將原函數(shù)func轉變成一個全新的函數(shù),這個全新函數(shù)的this值永遠是參數(shù)thisValue指定的值,并且它的初始參數(shù)包含了從arg1開始到最后的所有參數(shù).當調(diào)用這個新函數(shù)時,新添加的參數(shù)會跟隨在那些已有的通過bind綁定的參數(shù)后面.MDN上有更詳細的資料.注意上面的例子中,第一個參數(shù)是null,因為Date函數(shù)并不需要一個thisValue:在作為構造函數(shù)調(diào)用時,new運算符會覆蓋掉通過bind指定的thisValue.
第二步.我們想把數(shù)組傳給bind.所以再次使用了apply,將一個數(shù)組轉換為展開的參數(shù)傳遞給bind函數(shù).
new (Function.prototype.bind.apply(
Date, [null].concat([2011, 11, 24])))
我們在函數(shù)Function.prototype.bind上調(diào)用apply方法,帶有兩個參數(shù):
•第一個參數(shù): this的值指定為Date, 也就相當于上面寫的的Date.bind(...).
•第二個參數(shù): 傳給bind方法的參數(shù),null和后面的數(shù)組[2011, 11, 24]連接成的新數(shù)組.
3.2 一個庫函數(shù)
Mozilla建議將上述工作封裝成一個庫方法.下面的代碼正是在它們的建議之上稍微修改了一下:
if (!Function.prototype.construct) {
Function.prototype.construct = function(argArray) {
if (! Array.isArray(argArray)) {
throw new TypeError("Argument must be an array");
}
var constr = this;
var nullaryFunc = Function.prototype.bind.apply(
constr, [null].concat(argArray));
return new nullaryFunc();
};
}
運行一下:
> Date.construct([2011, 11, 24])
Sat Dec 24 2011 00:00:00 GMT+0100 (CET)
3.3 一個看似更簡單的解決方案
你可以手動實現(xiàn)new運算符的操作.例如:
var foo = new Foo("abc");
實際上等同于:
var foo = Object.create(Foo.prototype);
Foo.call(foo, "abc");
根據(jù)這個原理,我們可以寫一個簡單的庫方法:
Function.prototype.construct = function(argArray) {
var constr = this;
var inst = Object.create(constr.prototype);
constr.apply(inst, argArray);
return inst;
};
唉!Date作為一個普通函數(shù)來調(diào)用和作為一個構造函數(shù)來調(diào)用是一樣的:它會忽略掉call()和apply()方法中第一個參數(shù)指定的this值,總會生成并返回一個新的實例.
譯者注:這里作者理解錯了,Date作為普通函數(shù)調(diào)用和作為構造函數(shù)來調(diào)用是完全不一樣的.不加new的情況下,無論有沒有參數(shù),Date()只會返回當前時間的字符串,也就是(new Date()).toString()
> Date.construct([2011, 11, 24])
{}
譯者注:內(nèi)置的構造函數(shù)中,Array(),Function(),RegExp(),Error()等構造函數(shù)在調(diào)用時,加new或不加幾乎一樣.比如Array(10)也是生成一個數(shù)組,但Number(),String(),Boolean()就不一樣了.不加new它們是類型轉換函數(shù),返回的是原始值,加new是構造函數(shù),返回的是對象值.
>typeof Number("1")
"number"
>typeof new Number("1")
"object"
正如你所看到的,在操作Date()方法時,我們所寫的這個construct()方法并不能如期工作,而且還有一些其他的內(nèi)置構造函數(shù)也表現(xiàn)的和Date一樣.不過如果是在操作一個庫中自定義的構造函數(shù)的時候,這個方法基本可以正常工作(少部分構造函數(shù)返回了自己指定的對象值,而不是返回了默認的自動生成的實例this).
譯者注:一個構造函數(shù)的return語句只要返回的是個對象值,就會覆蓋掉默認的this值.比如:
function Func1(){
this.value = "this"; return {}
}
function Func2(){
this.value = "this"; return 1}function Func3(){ this.value = "this";}>new Func1() //返回的{}是個對象值,覆蓋了默認的this.{}>new Func2() //返回的1是個原始值,所以仍然返回默認的this.{value:"this"}>new Func3() //沒有return語句,默認返回了undefined,是個原始值,所以仍然返回默認的this.{value:"this"}>new Func3 //沒有參數(shù)時,小括號可以省略.{value:"this"}
相關文章
js RuntimeObject() 獲取ie里面自定義函數(shù)或者屬性的集合
取得ie 里面 自定義函數(shù)或者屬性的集合 使用RuntimeObject()實現(xiàn),需要的朋友可以參考下。2010-11-11動態(tài)創(chuàng)建script標簽實現(xiàn)跨域資源訪問的方法介紹
本篇文章主要是對動態(tài)創(chuàng)建script標簽實現(xiàn)跨域資源訪問的方法進行了介紹,需要的朋友可以過來參考下,希望對大家有所幫助2014-02-02利用js實現(xiàn)在瀏覽器狀態(tài)欄顯示訪問者在本頁停留的時間
本文為大家介紹下利用JavaScript實現(xiàn)在瀏覽器狀態(tài)欄顯示停留時間即在狀態(tài)欄上顯示訪問者在本頁停留的時間2013-12-12JavaScript關于某元素點擊事件的監(jiān)聽和觸發(fā)
本文主要介紹了JavaScript關于某元素點擊事件的監(jiān)聽和觸發(fā),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-07-07