bind()
語法:
fun.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg:當(dāng)綁定函數(shù)被調(diào)用時(shí)姻成,該參數(shù)會(huì)作為原函數(shù)運(yùn)行時(shí)的 this 指向。當(dāng)使用new操作符調(diào)用綁定函數(shù)時(shí)愿棋,該參數(shù)無效科展。
arg1, arg2, ...:當(dāng)綁定函數(shù)被調(diào)用時(shí),這些參數(shù)將置于實(shí)參之前傳遞給被綁定的方法糠雨。
return:返回由指定的this值和初始化參數(shù)改造的原函數(shù)拷貝
bind() 函數(shù)會(huì)創(chuàng)建一個(gè)新函數(shù)(稱為綁定函數(shù))才睹,新函數(shù)與被調(diào)函數(shù)(綁定函數(shù)的目標(biāo)函數(shù))具有相同的函數(shù)體。
當(dāng)新函數(shù)被調(diào)用時(shí) this 值綁定到 bind() 的第一個(gè)參數(shù)甘邀,該參數(shù)不能被重寫琅攘。綁定函數(shù)被調(diào)用時(shí),bind() 也接受預(yù)設(shè)的參數(shù)提供給原函數(shù)松邪。一個(gè)綁定函數(shù)也能使用new運(yùn)算符創(chuàng)建一個(gè)用戶定義的對(duì)象類型的實(shí)例或具有構(gòu)造函數(shù)的內(nèi)置對(duì)象的實(shí)例坞琴。")操作符創(chuàng)建對(duì)象:這種行為就像把原函數(shù)當(dāng)成構(gòu)造器。提供的 this 值被忽略逗抑,同時(shí)調(diào)用時(shí)的參數(shù)被提供給模擬函數(shù)剧辐。————MDN
創(chuàng)建綁定函數(shù)
bind() 最簡(jiǎn)單的用法是創(chuàng)建一個(gè)函數(shù)锋八,使這個(gè)函數(shù)不論怎么調(diào)用都有同樣的 this 值浙于。
this.x = 9;
var obj = {
x: 81,
GetObjx: function() {
console.log(this.x);
}
};
obj.GetObjx(); // 81
var againGetObjx = obj.GetObjx;
againGetObjx(); // 9 無法獲取到obj.x护盈,因?yàn)榇藭r(shí)的this指向Window
// 創(chuàng)建一個(gè)新函數(shù)挟纱,將this綁定到obj對(duì)象
var fn = againGetObjx.bind(obj);
fn(); // 81
上例中,againGetObjx引用了obj對(duì)象中的GetObjx方法腐宋,但是很顯然紊服,this.x沒有指向obj,是因?yàn)樾鼐海藭r(shí)調(diào)用againGetObjx的對(duì)象是全局對(duì)象欺嗤,理所當(dāng)然的this引用指向window,打印出window.x卫枝,即9
煎饼。
使用bind()方法,在方法中我們傳入了obj對(duì)象校赤,強(qiáng)制指定了函數(shù)執(zhí)行上下文吆玖,將this綁定到了obj對(duì)象筒溃。
偏函數(shù)
bind()的另一個(gè)最簡(jiǎn)單的用法是使一個(gè)函數(shù)擁有預(yù)設(shè)的初始參數(shù)。這些參數(shù)(如果有的話)作為bind()的第二個(gè)參數(shù)跟在this(或其他對(duì)象)后面沾乘,之后它們會(huì)被插入到目標(biāo)函數(shù)的參數(shù)列表的開始位置怜奖,傳遞給綁定函數(shù)的參數(shù)會(huì)跟在它們的后面。
function list() {
return Array.prototype.slice.call(arguments);
}
var list1 = list(1,2,3);
console.log(list1); // [1,2,3];
var leadingThirtysevenList = list.bind(undefined,37);
var list2 = leadingThirtysevenList(); // [37]
console.log(list2);
var list3 = leadingThirtysevenList(1,2,3);
console.log(list3); // [37,1,2,3]
函數(shù)中的arguments保存著傳入實(shí)參翅阵,但本身是類數(shù)組歪玲,沒有數(shù)組的方法,所以使用數(shù)組"類"中的slice方法來代替掷匠。
var leadingThirtysevenList = list.bind(undefined,37);
實(shí)測(cè)滥崩,把undefined換成null也可以,表示不為this指定對(duì)象槐雾,函數(shù)體執(zhí)行不變夭委,那么在bind()方法第二個(gè)參數(shù)傳入的值會(huì)作為fn.bind()
中fn的參數(shù)一起傳入,在這就是list()函數(shù)了募强。
改寫:
function Fn(a,b,c) {
console.log(a);
console.log(b);
console.log(c);
return a+b+c;
}
var fn = Fn.bind(undefined,10);
console.log(
fn(20,30)
);
/*
10
20
30
60
*/
當(dāng)然株灸,如果在bind()方法中傳入足夠的參數(shù),那么后續(xù)的參數(shù)就不會(huì)生效擎值,但是它依然存在在arguments類數(shù)組中慌烧。
function Fn(a,b,c) {
console.log(a);
console.log(b);
console.log(c);
console.log(arguments);
return a+b+c;
}
var fn = Fn.bind(undefined,10,1,2);
console.log(
fn(20,30) // 參數(shù)無效,但仍有arguments類數(shù)組保存
);
/*
10
1
2
13
[10,1,2,20,30]
*/
配合 setTimeout
在默認(rèn)情況下,使用window.setTimeout()時(shí)鸠儿,this關(guān)鍵字會(huì)指向全局或者對(duì)象屹蚊。當(dāng)使用類的方法時(shí),需要 this 引用類的實(shí)例进每,你可能需要顯式地把 this 綁定到回調(diào)函數(shù)以便繼續(xù)使用實(shí)例汹粤。
function fn() {
console.log(this.petalCount);
}
function LateBloomer() {
this.petalCount = Math.ceil(Math.random() * 12) + 1;
}
LateBloomer.prototype.bloom = function() {
window.setTimeout(this.declare.bind(this),1000);
}
LateBloomer.prototype.declare = function() {
console.log("I am beautiful flower with " + this.petalCount + "petals!");
};
var flower = new LateBloomer();
flower.bloom(); // 一秒后,調(diào)用declare方法
apply()
apply()
方法調(diào)用一個(gè)函數(shù), 其具有一個(gè)指定的this
值田晚,以及作為一個(gè)數(shù)組提供的參數(shù)嘱兼。
調(diào)用有指定this值和參數(shù)的函數(shù)的結(jié)果。
func.apply(thisArg, [argsArray])
簡(jiǎn)單理解用法:
var obj = {
a: 1,
sum: function(b,c) {
console.log(this.a + b + c);
}
}
var obj2 = {
a: 2
}
obj.sum.apply(obj2,[5,5]); // 12
與構(gòu)造函數(shù):
function Ball(shape) {
this.shape = shape;
this.Pi = Math.PI;
}
function FootBall(shape,color) {
Ball.apply(this , arguments);
this.color = color,
this.say = function() {
console.log("shape:" + this.shape + " this.color:" + this.color);
}
}
var football = new FootBall("sphere","black");
football.say(); // shape:sphere this.color:black
函數(shù)只不過是在特定環(huán)境中執(zhí)行代碼的對(duì)象贤徒,因此通過apply和call方法也可以在新創(chuàng)建的對(duì)象上執(zhí)行構(gòu)造函數(shù)
使用apply來鏈接構(gòu)造器:
Function.prototype.construct = function (aArgs) {
var oNew = Object.create(this.prototype);
console.log(this.prototype === MyConstructor.prototype); // true
this.apply(oNew, aArgs); // this為構(gòu)造函數(shù)芹壕,以oNew(構(gòu)造函數(shù)的prototype)為上下文環(huán)境,傳入aArgs數(shù)組
console.log(this);
return oNew;
};
function MyConstructor() {
for (var nProp = 0;nProp < arguments.length; nProp++) {
this["property" + nProp] = arguments[nProp];
}
}
var myArray = [4, "Hello world!", false];
var myInstance = MyConstructor.construct(myArray);
console.log(myInstance.property1); // Hello world!
console.log(myInstance instanceof MyConstructor); // true
console.log(myInstance.constructor === MyConstructor); // true
console.log(myInstance.__proto__.constructor === MyConstructor); // true
construct()方法改寫(可能這樣更易讀):
Function.prototype.construct = function (aArgs) {
var oNew = {};
oNew.__proto__ = this.prototype;
this.apply(oNew, aArgs);
return oNew;
};
apply借調(diào)內(nèi)置函數(shù)
console.log(Math.max(1,2,3)) // 3
// 借用Math.max()
var numbers = [5,6,2,3,7];
var max = Math.max.apply(null,numbers);
console.log(max); // 7
// 借用Math.min()
var min = Math.min.apply(undefined,numbers);
console.log(min); // 2
call()
call() 方法調(diào)用一個(gè)函數(shù), 其具有一個(gè)指定的this值和分別地提供的參數(shù)(參數(shù)的列表)接奈。返回值是你調(diào)用的方法的返回值踢涌,若該方法沒有返回值,則返回undefined序宦。
fun.call(thisArg, arg1, arg2, ...)
語法層面睁壁,與apply不同就是,call()方法傳遞的是一個(gè)參數(shù)列表,apply傳遞的是參數(shù)數(shù)組潘明。
常用用法:使用call方法調(diào)用函數(shù)并且指定上下文的this
function greet() {
var reply = [this.person, 'Is An Awesome', this.role].join(' ');
console.log(reply);
}
var i = {
person: 'Douglas Crockford', role: 'Javascript Developer'
};
greet.call(i);
調(diào)用父構(gòu)造函數(shù)的call方法來實(shí)現(xiàn)繼承
function Product(name,price) {
this.name = name;
this.price = price;
}
function Food(a,b,category) {
Product.call(this,a,b);
this.category = category;
}
var food = new Food("sour apple",5,"sour");
console.log(food); // Food {name: "sour apple", price: 5, category: "sour"}
使用call方法調(diào)用匿名函數(shù)
var animals = [
{ species: "Lion", name: "King" },
{ species: "Whale", name: "Fail" }
]
for (var i = 0; i < animals.length; i++) {
(function (i) {
console.log("#" + i + " " + this.species + ": " + this.name);
}).call(animals[i], i)
}
// #0 Lion: King
// #1 Whale: Fail