一携狭、函數(shù)4種調(diào)用的方式
- 1.函數(shù)模式
- 2.方法模式
- 3.構造函數(shù)模式
- 4.上下文模式(也有叫apply模式)
apply, call, bind用法
在JavaScript 中砰识,call、apply 和 bind 是 Function 對象自帶的三個方法泡一,這三個方法的主要作用是改變函數(shù)調(diào)用過程中的 this 指向
1. apply(thisArgs[,args[]])
- 第一個參數(shù)指定函數(shù)體內(nèi)this對象的指向
thisArgs 的取值有以下4種情況:- 不傳留潦,或者傳
null
,undefined
鸭叙, 非嚴格模式下 函數(shù)中的this
指向window
對象闯第。 嚴格模式下不傳
、undefined
函數(shù)中this
指向undefined
旺聚。傳入null
函數(shù)中this
指向null
- 傳遞另一個函數(shù)的函數(shù)名织阳,函數(shù)中的
this
指向這個函數(shù)的引用 - 傳遞字符串、數(shù)值或布爾類型等基礎類型砰粹,非嚴格模式函數(shù)中的
this
指向其對應的包裝對象唧躲,如String
、Number
、Boolean
惊窖。嚴格模式刽宪,指向傳入的值 - 傳遞一個對象,函數(shù)中的
this
指向這個對象
- 不傳留潦,或者傳
- 第二個參數(shù)為一個帶下標的集合界酒,可以是數(shù)組或類數(shù)組,apply方法把這個集合中的元素作為參數(shù)傳遞給被調(diào)用的函數(shù)
var func = function(a, b, c) {
console.log([a, b, c]); // [1,2,3]
}
func.apply(null, [1,2,3])
apply 和 call 的唯一區(qū)別是第二個參數(shù)的傳遞方式不同圣拄,apply 的第二個參數(shù)必須是一個數(shù)組,而 call 允許傳遞一個參數(shù)列表毁欣。值得你注意的是庇谆,雖然 apply 接收的是一個參數(shù)數(shù)組,但在傳遞給調(diào)用函數(shù)時凭疮,卻是以參數(shù)列表的形式傳遞饭耳,我們看個簡單的例子:
function b(x,y,z){
console.log(x,y,z);
}
b.apply(null,[1,2,3]); // 1 2 3
2. call(thisArgs [,args...])
該方法可以傳遞一個thisArgs參數(shù)和一個參數(shù)列表,thisArgs 指定了函數(shù)在運行期的調(diào)用者执解,也就是函數(shù)中的 this 對象寞肖,而參數(shù)列表會被傳入調(diào)用函數(shù)中。
thisArgs 的取值有以下4種情況:
- 不傳衰腌,或者傳
null
,undefined
新蟆, 非嚴格模式下 函數(shù)中的this
指向window
對象。 嚴格模式下不傳
右蕊、undefined
函數(shù)中this
指向undefined
琼稻。傳入null
函數(shù)中this
指向null
- 傳遞另一個函數(shù)的函數(shù)名,函數(shù)中的
this
指向這個函數(shù)的引用 - 傳遞字符串饶囚、數(shù)值或布爾類型等基礎類型帕翻,非嚴格模式函數(shù)中的
this
指向其對應的包裝對象,如String
萝风、Number
嘀掸、Boolean
。嚴格模式规惰,指向傳入的值 - 傳遞一個對象横殴,函數(shù)中的
this
指向這個對象
function a(){
console.log(this); //輸出函數(shù)a中的this對象
}
function b(){} //定義函數(shù)b
var obj = {name:'onepixel'}; //定義對象obj
// 嚴格模式
a.call(); //undefined
a.call(null); //null
a.call(undefined);//undefined
a.call(1); //1
a.call(''); // ''
a.call(true); //true
a.call(b);// function b(){}
a.call(obj); //Object
// 非嚴格模式
a.call(); //window
a.call(null); //window
a.call(undefined);//window
a.call(1); //Number
a.call(''); //String
a.call(true); //Boolean
a.call(b);// function b(){}
a.call(obj); //Object
當使用call或則apply的時候,如果我們傳入的第一個參數(shù)是null.函數(shù)體內(nèi)的this會指向默認的宿主對象卿拴,在游覽器中則是window
var func = function( a, b, c ){
alert ( this === window ); // 輸出true
};
func.apply( null, [ 1, 2, 3 ] );
但如果是在嚴格模式下,函數(shù)體內(nèi)的this還是為null:
var func = function( a, b, c ){
"use strict";
alert ( this === null ); // 輸出true
}
func.apply( null, [ 1, 2, 3 ] );
有時候我們使用call或者apply的目的不在于指定this指向梨与,而是另有用途堕花,比如借用其他對象的方法。
那么我們可以傳入null來代替某個具體的對象:
Math.max.apply( null, [ 1, 2, 5, 3, 4 ] ) // 輸出:5
call和apply的用途
確定函數(shù)內(nèi)部this指向
var obj1={
name: '李小龍'
}
var obj2={
name: '蕭薰'
}
window.name = 'window'
var getName = function(){
console.log(this.name)
};
getName(); //輸出:window
getName.call(obj1); //輸出:李小龍
getName.call(obj2); //輸出:蕭薰
當執(zhí)行getName.call( obj1 )這句代碼時粥鞋,getName函數(shù)體內(nèi)的this就指向obj1對象
- this 錯誤的情況
document.getElementById( 'div1' ).onclick = function(){
alert( this.id ); // 輸出:div1
var func = function(){
alert ( this.id ); // 輸出:undefined
}
func();
};
- 修正this
document.getElementById( 'div1' ).onclick = function(){
var func = function(){
alert ( this.id ); // 輸出:div1
}
func.call( this );
};
3. bind(thisArgs [,args...])
bind是ES5 新增的一個方法缘挽,它的傳參和call類似,但又和 call/apply 有著顯著的不同,即調(diào)用 call 或 apply 都會自動執(zhí)行對應的函數(shù)壕曼,而 bind 不會執(zhí)行對應的函數(shù)苏研,只是返回了對函數(shù)的引用。粗略一看腮郊,bind 似乎比call/apply 要落后一些摹蘑,那ES5為什么還要引入bind 呢?
其實轧飞,ES5引入 bind 的真正目的是為了彌補 call/apply 的不足衅鹿,由于 call/apply 會對目標函數(shù)自動執(zhí)行,從而導致它無法在事件綁定函數(shù)中使用过咬,因為事件綁定函數(shù)不需要我們手動執(zhí)行大渤,它是在事件被觸發(fā)時由JS 內(nèi)部自動執(zhí)行的。而 bind 在實現(xiàn)改變函數(shù) this 的同時又不會自動執(zhí)行目標函數(shù)掸绞,因此可以完美的解決上述問題泵三,看一個例子就能明白:
var obj = {name:'onepixel'};
/**
* 給document添加click事件監(jiān)聽,并綁定onClick函數(shù)
* 通過bind方法設置onClick的this為obj衔掸,并傳遞參數(shù)p1,p2
*/
document.addEventListener('click',onClick.bind(obj,'p1','p2'),false);
//當點擊網(wǎng)頁時觸發(fā)并執(zhí)行
function onClick(a,b){
console.log(
this.name, //onepixel
a, //p1
b //p2
)
}
參考JavaScript設計模式與開發(fā)實踐 烫幕、 一像素 博客園