js基礎知識---call,apply,bind的用法

call,apply詳解

javascript中,call和apply方法的用途是為了擴充函數賴以生存的作用域,通俗點來說,就是為了動態改變函數體內部this的指向。
用途: 擴充函數賴以生存的作用域。
好處: 對象與方法之間不需要任何的耦合關系。
javascript的一大特點是,函數存在定義時上下文運行時上下文,和上下文是可變的,這樣的概念。

先上一個例子:

function showColor(){
    console.log("my color is:" + this.color);
}
window.color = "red";

showColor.call(window);    //my color is:red

上面的例子中,shouwColor函數并沒有對外部調用自己傳入的參數進行接收,那么調用者是怎么樣通過調用該函數來得到想要的結果呢?
先來解釋下,上面這段代碼。代碼中,定義了一個showColor函數,以及一個掛載在window下的一個全局對象color,showColor.call(this)執行了shouwColor函數,并且改變了shouwColor函數中this的指向,call方法傳入的第一個參數,始終代表著this的指向。當傳入的第一個參數是window的時候,shouwColor函數中的this就指向了window,那么this.color就相當于window.colorl了,打印出來的結果就自然是window.color的值了。

var colorObj = {"color":"blue"};
showColor.call(colorObj);    //my color is:blue

那么我們再來定義一個colorObj 對象,對象中,有一個屬性color,call方法中第一個參數是colorObj 對象,那么一樣的道理,shouwColor函數中的this就指向了**colorObj **對象了。這就是call方法的簡單運用了。

call,apply方法的定義

call方法:
語法:call([thisObj[,arg1[, arg2[, [,.argN]]]]])
定義:調用一個對象的一個方法,以另一個對象替換當前對象。
說明:
call 方法可以用來代替另一個對象調用一個方法。call 方法可將一個函數的對象上下文從初始的上下文改變為由 thisObj 指定的新對象。
如果沒有提供 thisObj 參數,那么 window 對象被用作 thisObj。

apply方法:
語法:apply([thisObj[,argArray]])
定義:應用某一對象的一個方法,用另一個對象替換當前對象。
說明:
如果 argArray 不是一個有效的數組或者不是 arguments 對象,那么將導致一個 TypeError。
如果沒有提供 argArray 和 thisObj 任何一個參數,那么 window 對象將被用作 thisObj, 并且無法被傳遞任何參數。

call,apply方法的區別

對于 apply、call 二者而言,作用完全一樣,只是接受參數的方式不太一樣。例如,有一個函數定義如下:

function test(arg1,arg2){
    ......
}

就可以通過以下方式調用了

test.call(this,arg1,arg2);
test.apply(this,[arg1,arg2]);

其中 this 是你想指定的上下文,可以是任何一個 JavaScript 對象(JavaScript 中一切皆對象),call 需要把參數按順序傳遞進去,而 apply 則是把參數放在數組里。

call,apply方法的示例

1.數組的合并

var facebookImg = ["fb1.jpg","fb2.jpg","fb3.jpg"];
var youtubeImg = ["yt1.jpg","yt2.jpg","yt3.jpg"];
Array.prototype.push.apply(facebookImg,youtubeImg); //返回值為合并后的facebookImg數組的長度

facebookImg的值為: ["fb1.jpg","fb2.jpg","fb3.jpg","yt1.jpg","yt2.jpg","yt3.jpg"]
或者合并后賦值給一個新數組(不改變原數組的值)

var facebookImg = ["fb1.jpg","fb2.jpg","fb3.jpg"];
var youtubeImg = ["yt1.jpg","yt2.jpg","yt3.jpg"];
var allImg = [];
allImg.push.apply(allImg,facebookImg);
allImg.push.apply(allImg,youtubeImg);

2.獲取數組中的最大值和最小值
js獲取數組中的最大值和最小值,有多種方法,比如冒泡排序等,使用apply和call方法也是可以達到相同的效果的。

var  numbers = [5, 458 , 120 , -215 ]; 
var applyMaxInNumbers = Math.max.apply(Math, numbers);   //458
var applyMinInNumbers = Math.min.apply(Math,numbers); //-215

number 本身沒有 max 方法,但是 Math 有,我們就可以借助 call 或者 apply 使用其方法。

3.類(偽)數組使用數組方法
Javascript中存在一種名為偽數組的對象結構。比較特別的是 arguments 對象,還有像調用 getElementsByTagName , document.childNodes 之類的,它們返回NodeList對象都屬于偽數組。不能應用 Array下的 push , pop 等方法。
但是我們能通過 Array.prototype.slice.call 轉換為真正的數組的帶有 length 屬性的對象,這樣 domNodes 就可以應用 Array 下的所有方法了。

4.定義一個 log 方法,讓它可以代理 console.log 方法
一般我們都會去這樣的實現:

function log(msg){
    console.log(msg);
}
log("testData1");          //testData1
log("data1","data2");      //data1

上面的這種實現的方式在傳入一個參數的時候是滿足要求的,但是當傳入的參數是多個的話,就失效了,因為log方法只接受了第一個且唯一一個參數。那么如果要在傳入多個參數的情況下也能夠實現,就可以用到call和apply方法了,注意,當不清楚參數的具體個數時,建議最好運用apply方法。

function log(){
    console.log.apply(window,arguments);
}
log("testData1");          //testData1
log("data1","data2","data3");      //data1,data2,data3

接下來的要求是給每一個 log 消息添加一個"(doView)"的前輟,比如:

log("hello world");    //(doView)hello world

那么就可以利用偽數組轉為標準數組的方式,然后再使用unshift方法操作數組

function log(){
  var argsData = Array.prototype.slice.call(arguments);
  argsData.unshift('(doView)');
  console.log.apply(window, args);
};

5.借用構造函數繼承的實現
javascript中的繼承方式實現由多種,包括原型繼承,借用構造函數繼承與組合繼承等。那么現在就用call和apply方法來簡單實現下javascript中的構造函數的繼承吧。

function superType(name){
    this.name = name;
}
function subType(name,age){
    this.age = age;
    superType.call(this,name);
}
var types1 = new subType("yqxcn", 30);
console.log("age:" + types1.age);        //age:30
console.log("name:" + types1.name);      //name:yqxcn,繼承自superType屬性值

var types2 = new subType("wx272252", 18);
console.log("age:" + types2.age);        //age:18
console.log("name:" + types2.name);      //name:wx272252,繼承自superType屬性值

bind的用法

bind方法雖然與call,apply的用法有點不同,但是其作用也是一樣的,也是可以改變函數體內this的指向。
MDN的解釋是:bind()方法會創建一個新函數,稱為綁定函數,當調用這個綁定函數時,綁定函數會以創建它時傳入 bind()方法的第一個參數作為 this,傳入 bind() 方法的第二個以及以后的參數加上綁定函數運行時本身的參數按照順序作為原函數的參數來調用原函數。

以最開始的例子為例:

function showColor(){
    console.log("my color is:" + this.color);
}
window.color = "red";
showColor.bind(window);      //這里并不會打印出想要的結果

這個例子就可以很好的證明了上面MDN的解釋了,當瀏覽器執行"showColor.bind(window); "這一句代碼的時候,bind()創建了一個綁定函數,也就是說這句代碼只是創建了一個函數,卻并沒有調用執行該函數,就像我們自己定義了一個普通函數而沒有調用它,所以這句代碼需要改成如下:

showColor.bind(window)();    //my color is:red

這也是apply、call、bind的不同之處。bind方法是創建一個函數,然后可以在需要調用的時候再執行函數,并非是立即執行函數;而call,apply是在改變了上下文中的this指向后并立即執行函數。

總結

  • call,apply,bind都是可以改變函數體內this的指向。
  • call,apply,bind使用時,傳入的第一個參數都是用來傳遞this的指向的,也就是對上下文的指定。
  • call,apply,bind都是可以傳入多個參數,不同的是,call和bind的后續參數都是按照順序傳參,而apply的傳參類型是數組;bind的參數可以在函數執行的時候再次添加。

原創文章,站在前輩們的經驗上的總結,文中如有不正之處,還望指正!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,746評論 2 370

推薦閱讀更多精彩內容