詳解JavaScript中的this硬綁定
一、this顯示綁定
this顯示綁定,顧名思義,它有別于this的隱式綁定,而隱式綁定必須要求一個對象內部包含一個指向某個函數的屬性(或者某個對象或者上下文包含一個函數調用位置),并通過這個屬性間接調用這個函數,從而把this簡介/隱式綁定到這個對象上。但是this的隱式綁定存在一個綁定對象丟失問題,如下面代碼所示:
function afun() {
console.log(this.a);
}
var obj = {
a: 1,
afun: afun
};
var a = "hello";
setTimeout(obj.afun, 100);//"hello"
出人意料的是,控制臺打印出來的結果是全局變量a的結果,而不是擁有指向函數屬性的對象的a的值,這就是隱式綁定的對象丟失,回調函數丟失綁定對象是非常常見的。
但是,顯示綁定仍然不能解決綁定對象丟失的問題,但是顯示綁定的一個變種,即硬綁定可以解決綁定對象丟失。
在此之前,我們先來看看什么是顯示綁定。
我們可以通過使用函數的call()和apply()方法實現this顯示綁定,絕大多數內置函數和自定義函數都可以調用這兩種方法。他們均接收兩個參數
參數:
thisArg: 要綁定到調用者this的對象。
arg1, arg2, ...(call):指定的參數列表,即要傳給調用者的參數。比如a.call(obj, args)/a.apply(obj, args),args為參數傳給調用者函數a作為該函數的實參。
argsArray(apply):一個數組或者類數組對象,如果該參數的值為 null 或 undefined,則表示不需要傳入任何參數。
返回值:調用者函數若有返回值則返回該值,沒有返回值則返回undefined。
來看下面的代碼:
function bfun() {
return this.a;
}
var obj1 = {
a: "hello"
};
console.log(bfun.apply(obj1), bfun.call(obj1));//"hello" "hello"
若傳入的第一個參數時一個原始值呢?來看下面的代碼:
function bfun() {
return this;
}
console.log(bfun.apply(3));//[Number: 2]
沒錯,原始值被轉換成了它的對象形式,也就是new Number(),這被成為"裝箱"。
但是,我們前面提到過,this顯示綁定雖然強大,但是仍然不能解決this綁定丟失問題。下面我們來解釋硬綁定,即顯示綁定的一個變種,它能完美解決this綁定丟失問題。
二、硬綁定
先來看看下面的代碼:
function cfun() {
console.log(this.a)//"hello"
return this.a;
}
var obj2 = {
a: "hello"
};
var fn = function() {
return cfun.apply(obj2);
};
console.log(fn());//"hello"
setTimeout(fn, 100);//"hello"
可以看到,硬綁定確實解決了this綁定丟失,但值得注意的是,通過apply()綁定的this對象,無法二次更改綁定對象:
function f() {
console.log( this.a );
}
var obj = {
a:2
};
var b = function() {
f.call( obj );
};
b(); // 2
b.call( window ); // 2
硬綁定的一個典型應用場景是創(chuàng)建一個包裹函數,傳入所有的參數給調用者函數并返回接收到的所有值。
function dfun(v) {
return (v[0] + this.a);
}
var obj3 = {
a: 10
};
var fn1 = function() {
return dfun.call(obj3, arguments);
}
var result = fn1(6);
console.log(result);//16
對于arguments而言,call()和apply()的不同之處在于他們的參數類型不同:
function efun(v) {
console.log(..v)//6 10 11
return (v);
}
var obj4 = {
a: 10
};
var fn1 = function() {
return efun.apply(obj3, arguments);
}
var result = fn1([6, 10, 11]);
console.log(result);//[6, 10, 11]
也就是說call()的參數類型是Object,它傳入的參數列表會被轉換為鍵為'0'(隨傳入參數數量遞增),值為傳入參數的對象;而apply()的參數類型則是數組或者類數組。
function dfun(v) {
return (v);
}
var obj3 = {
a: 10
};
var fn1 = function() {
return dfun.call(obj3, arguments);
}
var result = fn1(6, 19, 1, 1);
console.log(result);//[Arguments]{'0':6,'1':19,2':1,3':1}
console.log(typeof result);//'object'
最強大的一種方法是將包裹函數創(chuàng)建為可以重復使用的輔助函數,封裝可重復使用的硬綁定。
function ffun(v) {
return this.a * v;
}
var obj5 = {
a: 5,
};
var fn2 = function(fn, obj) {
return function() {
return fn.apply(obj, arguments);
}
}
var bind = fn2(ffun, obj5);
console.log(bind(10));//50
由于硬綁定十分常用,但通過包裹函數創(chuàng)建可重復使用的硬綁定比較麻煩,所以ES5提供了一個實現相同功能的方法bind()。用法如下:
function hfun(v) {
return this.a * v;
}
var obj6 = {
a: 6
};
var bind = hfun.bind(obj6);
console.log(bind(4));//24
可以看到,我們再無需構建一個包裹函數來手動調用call或apply方法,只需要提供調用者和綁定到調用者this的對象即可。
我們可能發(fā)現了一個奇怪的現象,通過apply()和call()方法綁定的對象在傳參給調用者時,需要設置一個參數占位,但bind()方法則不用,這是因為他們的返回值不同,bind()方法會返回一個經過硬編碼的新函數,它會把傳入參數設置為this的上下文并調用原始函數??梢岳斫鈈ind使用方法為bind(obj)(args)。而對于call()和apply()方法而言,一旦調用此方法,就會立刻返回調用者函數的返回值,所以此時就需要同時傳入參數給方法的參數占用符,然后被函數參數讀取。值得注意的是,bind方法的參數和call方法類似。
到此這篇關于詳解JavaScript中的this硬綁定 的文章就介紹到這了,更多相關JavaScript this硬綁定 內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- 一文全面解析JS中的this綁定規(guī)則
- JavaScript中this綁定規(guī)則你理解了嗎
- 細說JavaScript中的this指向與綁定規(guī)則
- JavaScript this綁定與this指向問題的解析
- JavaScript?中的?this?綁定規(guī)則詳解
- JavaScript中this的綁定你知道幾種?
- 一文搞懂JavaScript中的this綁定規(guī)則
- JavaScript中?this?的綁定指向規(guī)則
- 詳解JavaScript的this指向和綁定
- JavaScript this綁定過程深入詳解
- React.js綁定this的5種方法(小結)
- JavaScript調用模式與this關鍵字綁定的關系
- 深入理解JavaScript this綁定規(guī)則
相關文章
簡單聊聊JavaScript中作用域與自執(zhí)行函數的使用
作用域指的是一個變量的作用范圍,自執(zhí)行函數是指定義后立即執(zhí)行的函數,它可以被用來創(chuàng)建一個私有作用域,本文主要來和大家聊聊二者的具體定義與使用,感興趣的可以了解下2024-03-03
JavaScript talbe表中指定位置插入一行的實現代碼 腳本之家修正版
用js實現的在table中指定的位置插入一行,先點一下表中你想插入的位置,點擊即可。2009-06-06

