call/apply/bind的方法來源
call/apply/bind方法其實(shí)都來自與function.prototype,都屬于實(shí)例方法
console.log(Function.prototype.hasOwnproperty('call'));
console.log(Function.prototype.hasOwnproperty('apply'));
console.log(Function.prototype.hasOwnproperty('bind'));
//true true true
擴(kuò)展一下下:
Object.prototype.hasOwnProperty()方法用來判斷某個(gè)對(duì)象是否含有指定的自身屬性,返回true/false.
Object.prototype.isPrototypeOf()方法測(cè)試一個(gè)對(duì)象是否存在另一個(gè)對(duì)象的原型鏈上,返回true/false.
Function.prototype.call()
函數(shù)實(shí)例的call方法,可以指定函數(shù)this的指向,既函數(shù)執(zhí)行時(shí)的作用域诀紊。然后在指定的作用域內(nèi)調(diào)用該函數(shù),而且立即執(zhí)行。
var obj = {
num:123
}
var num = 456;
functon fn(){
console.log(this.num)
}
fn() //456
fn.call() //456
fn.call(null)//456
fn.call(undefined)//456
fn.call(this)//456
fn.call(obj)//123
從上邊可以看出fn函數(shù)的this在沒有操作或者call中的參數(shù)為空叨橱、null、undefined断盛、this的時(shí)候都指向的應(yīng)該是456罗洗。而當(dāng)參數(shù)改變。fn中this的指向改變钢猛,指向的是obj伙菜。所以是123.
call()方法可以傳遞兩個(gè)參數(shù)。第一個(gè)參數(shù)是指定函數(shù)內(nèi)部中this的指向(也就是函數(shù)執(zhí)行時(shí)所在的作用域)命迈,第二個(gè)參數(shù)是函數(shù)調(diào)用時(shí)需要傳遞的參數(shù)贩绕。
第一個(gè)參數(shù)是必須的,可以是null壶愤,undefined淑倾,this,但是不能為空征椒。設(shè)置為null娇哆,undefined,this表明函數(shù)keith此時(shí)處于全局作用域勃救。第二個(gè)參數(shù)中必須一個(gè)個(gè)添加碍讨。而在apply中必須以數(shù)組的形式添加。
Function.prototype.apply()
apply方法的作用與call方法類似剪芥,也是改變this指向(函數(shù)執(zhí)行時(shí)所在的作用域)垄开,然后在指定的作用域中,調(diào)用該函數(shù)税肪。同時(shí)也會(huì)立即執(zhí)行該函數(shù)溉躲。唯一的區(qū)別就是,它接收一個(gè)數(shù)組作為函數(shù)執(zhí)行時(shí)的參數(shù)益兄。
apply方法的實(shí)例應(yīng)用
找出數(shù)組中最大的數(shù)
var arr = [1,2,3,4,58,6]
console.log(Math.max.apply(null,arr))
Javascript中是沒有提供找出數(shù)組中最大值的方法的锻梳,結(jié)合使用繼承自Function.prototype的apply和Math.max方法,就可以返回?cái)?shù)組的最大值净捅。
將數(shù)組的空元素變?yōu)閡ndefined
console.log(Array.apply(null, [1, , 3])); // [1, undefined, 3]
空元素與undefined的差別在于疑枯,數(shù)組的forEach方法會(huì)跳過空元素,但是不會(huì)跳過undefined和null蛔六。因此荆永,遍歷內(nèi)部元素的時(shí)候废亭,會(huì)得到不同的結(jié)果。
var a = [1, , 3];
a.forEach(function(index) {
console.log(index); //1,3 具钥,跳過了空元素豆村。
})
Array.apply(null,a).forEach(function(index){
console.log(index); ////1,undefined,3 做入,將空元素設(shè)置為undefined
})
轉(zhuǎn)換類似數(shù)組的對(duì)象
利用數(shù)組對(duì)象的slice方法立膛,可以將一個(gè)類似數(shù)組的對(duì)象(比如arguments對(duì)象)轉(zhuǎn)為真正的數(shù)組。當(dāng)然记餐,slice方法的一個(gè)重要應(yīng)用宁玫,就是將類似數(shù)組的對(duì)象轉(zhuǎn)為真正的數(shù)組粗恢。call和apply都可以實(shí)現(xiàn)該應(yīng)用。
console.log(Array.prototype.slice.apply({0:1,length:1})); //[1]
console.log(Array.prototype.slice.call({0:1,length:1})); //[1]
console.log(Array.prototype.slice.apply({0:1,length:2})); //[1,undefined]
console.log(Array.prototype.slice.call({0:1,length:2})); //[1,undefined]
function keith(a,b,c){
return arguments;
}
console.log(Array.prototype.slice.call(keith(2,3,4))); //[2,3,4]
上面代碼的call欧瘪,apply方法的參數(shù)都是對(duì)象眷射,但是返回結(jié)果都是數(shù)組,這就起到了將對(duì)象轉(zhuǎn)成數(shù)組的目的恋追。從上面代碼可以看到凭迹,這個(gè)方法起作用的前提是罚屋,被處理的對(duì)象必須有l(wèi)ength屬性苦囱,以及相對(duì)應(yīng)的數(shù)字鍵。
Function.prototype.bind()
bind方法用于指定函數(shù)內(nèi)部的this指向(執(zhí)行時(shí)所在的作用域)脾猛,然后返回一個(gè)新函數(shù)撕彤。bind方法并非立即執(zhí)行一個(gè)函數(shù)。
var keith = {
a: 1,
count: function() {
console.log(this.a++);
}
};
keith.count(); //1
keith.count(); //2
keith.count(); //3
上面代碼中猛拴,如果this.a指向keith對(duì)象內(nèi)部的a屬性羹铅,如果這個(gè)方法賦值給另外一個(gè)變量,調(diào)用時(shí)就會(huì)出錯(cuò)愉昆。
var keith = {
a: 1,
count: function() {
console.log(this.a++);
}
};
var f = keith.count;
f(); //NaN
上面代碼中职员,如果把count方法賦值給f變量,那么this對(duì)象指向不再是keith對(duì)象了跛溉,而是window對(duì)象焊切。而window.a默認(rèn)為undefined,進(jìn)行遞增運(yùn)算之后undefined++就等于NaN芳室。
為了解決這個(gè)問題专肪,可以使用bind方法,將keith對(duì)象里的this綁定到keith對(duì)象上堪侯,或者是直接調(diào)用嚎尤。
var f = keith.count.bind(keith);
f(); //1
f(); //2
f(); //3
keith.count.bind(keith)() //1
keith.count.bind(keith)() //2
keith.count.bind(keith)() //3
當(dāng)然,this也可以綁定到其他對(duì)象上伍宦。
var obj = {
a: 100
};
var f = keith.count.bind(obj);
f(); //100
f(); //101
f(); //102
同樣芽死,我們也可以給bind方法傳遞參數(shù)乏梁,第一個(gè)參數(shù)如果為null或者undefined或者this,會(huì)將函數(shù)內(nèi)部的this對(duì)象指向全局環(huán)境关贵;第二個(gè)為調(diào)用時(shí)需要的參數(shù)掌呜,并且傳遞參數(shù)的形式與call方法相同。
function keith(a, b) {
return a + b;
}
console.log(keith.apply(null,[1,4])); //5
console.log(keith.call(null,1,4)); //5
console.log(keith.bind(null, 1, 4)); //keith()
console.log(keith.bind(null, 1, 4)()); //5
綁定回調(diào)函數(shù)的對(duì)象
var o = {
f: function() {
console.log(this === o);
}
}
$('#button').on('click', function() {
o.f.apply(o);
//或者 o.f.call(o);
//或者 o.f.bind(o)();
});