談到this繫結規則要先找到函式執行過程中的呼叫位置。
呼叫位置就是函式在**中被呼叫的位置。這就涉及分析呼叫棧(就是為了到達當前執行位置所呼叫的所有函式)。呼叫位置就在當前正在執行的函式的前乙個呼叫中。
那什麼是呼叫棧和呼叫位置呢?
//1.呼叫棧和呼叫位置
function
baz(
)function
bar(
)function
foo(
)baz()
;//<-- baz的呼叫位置
呼叫棧是baz->bar->foo,當呼叫foo()時呼叫位置就是bar(),可以簡單理解為在bar()中呼叫foo().
注意是如何(從呼叫棧中)分析出真正的呼叫位置的,因為它決定了this的繫結。
this有四大繫結規則,下面來仔細看看這四大規則。
function
foo(
)var a=2;
foo();
//2
foo()是直接使用不帶任何修飾的函式引用進行呼叫的,因此只能使用預設繫結,無法應用其他規則
//嚴格模式下全域性物件將無法使用預設繫結,this會繫結到undefined. 嚴格模式下與foo()的呼叫位置無關
function
foo(
)var a=2;
foo();
//undefined
function
foo(
)var obj=
;obj.
foo();
//2
呼叫位置會使用obj上下文來引用函式。當foo()被呼叫時,它的落腳點指向obj物件。當函式引用有上下文物件時,隱式繫結規則會把函式呼叫中的this繫結到這個上下文物件,因此this.a和obj.a是一樣的。
物件屬性引用鏈中只有最頂層或者說最後一層會影響呼叫位置。舉例來說:
function
foo(
)var obj2=
;var obj1=
;obj1.obj2.
foo();
//42
隱式丟失
乙個最常見的this繫結問題就是被隱式繫結的函式會丟失繫結物件,也就是說它會應用預設繫結,從而把this繫結到全域性物件或者undefined上,取決於是否是嚴格模式。
//隱式丟失
function
foo(
)var obj=
;var bar=obj.foo;
//函式別名!bar引用的是foo函式本身
var a=
"hello febby"
;//a是全域性物件屬性
bar();
//hello febby
雖然bar只是obj.foo的乙個引用,實際上,它引用的是foo函式本身,因此此時的bar()其實是乙個不帶任何修飾的函式呼叫,因此應用了預設繫結。
同時注意區分下面這種呼叫方式
function
foo(
)var obj=
;var bar=obj.
foo();
//繫結到obj上
var a=
"hello febby"
;//a是全域性物件屬性
// bar; //2
console.
log(bar)
;//2
再來思考一下下面這段**:
function
foo(
)function
dofoo
(fn)
var obj=
;var a=
"hello febby"
;//a是全域性物件屬性
dofoo
(obj.foo)
;//hello febby
引數傳遞其實就是一種隱式賦值,因此我們傳入函式時也會被隱式賦值,所以結果跟上面一樣。
如果把函式傳入語言內建的函式而不是傳入自己宣告的函式,結果是一樣的。
function
foo(
)var obj=
;var a=
"hello febby"
;//a是全域性物件屬性
settimeout
(obj.foo,
100)
;//hello febby
//js環境中內建的settimeout()函式實現與下面偽**類似
function
settimeout
(fn,delay)
//顯式繫結
function
foo(
)var obj=
;foo.
call
(obj)
;//2
foo.
(obj)
;//2
硬繫結可以解決丟失繫結問題。
function
foo(
)var obj=
;var
bar=
function()
;bar()
;//2
settimeout
(bar,
100)
;//2
//硬繫結的bar不可能再修改它的this
bar.
call
(window)
//2
我們建立了bar(),並在它的內部手動呼叫了foo.call(obj),因此強制把foo的this繫結到了obj上。無論之後怎麼呼叫函式bar,它總會手動在obj上呼叫 foo。這種繫結是一種顯式的強制繫結,因此我們稱之為硬繫結。
new繫結
在js中,建構函式只是一些使用new操作符是被呼叫的函式。它們並不屬於某個類,也不會例項化乙個類。實際上,它們只是被new操作符呼叫的普通函式而已。
使用new來呼叫函式,或者說發生構造函式呼叫時,會自動執行下面的操作。
建立(或者說構造)乙個全新的物件。
這個新物件會被執行[[原型]]連線。
這個新物件會繫結到函式呼叫的this。
如果函式沒有返回其他物件,那麼new表示式中的函式會自動返回這個新物件。
//new繫結
function
foo(a)
var bar=
newfoo(2
);console.
log(bar.a)
;//2
使用new來呼叫foo(…)時,會構造乙個新物件並把它繫結到foo(…)呼叫中的this。
以上便是this四大繫結規則的總結,希望可以幫到大家。
具體用法傳送門:
this學習(三)this繫結規則的優先順序
目錄 一 顯式繫結 vs 隱式繫結 二 new繫結 vs 隱式繫結 三 顯示繫結 vs new繫結 四 總結 在前面的學習中,有預設繫結 顯式繫結 隱式繫結 new繫結,這4種規則當中,預設繫結的優先順序一定是最低的,那麼其它三個規則的優先順序到底是怎麼樣的呢?例子 function foo var...
2 3 this 繫結規則的優先順序
上篇 2.2this全面解析 了解到函式呼叫中this繫結的四條規則,找到函式的呼叫位置並判斷應當應用哪條規則。這篇學習假設某個呼叫位置可以應用多條規則,就必須給這些規則設定優先順序。毫無疑問,預設繫結的優先順序是四條規則中最低的,所以可以先不考慮它。function foo var obj1 va...
解讀IT架構管理中的四大重要規則
計算機系統的架構非常重要。不太合適的引用已故的green bay packers的傳奇教練vince lombardi話說,架構不是所有的事情,但是它是唯一的事情。或者曲解另乙個古老的說法,電腦程式潮起潮落,不好的架構永遠存在。通過觀察許多it部門的努力得出上述結論的。這些it部門的架構不能迅速改變...