綁定規則
this的綁定規則有四種
- 默認綁定 (全局對象或者undefined(嚴格模式下))
- 隱式綁定(調用時函數上下文對象,obj.fun())
- 顯式綁定(call , apply , bind(硬綁定))
- new綁定(新建的對象會被綁定到構造函數中的this上)
詳細介紹
1 . 默認綁定
調用沒有任何修飾函數時引用默認綁定,this指向全局對象
但是如果定義時使用嚴格模式(use strict),則不能將全局對象用於默認綁定,因此this會綁定到undefined,而在嚴格模式下調用卻不影響
2.隱式綁定
調用位置的上下文對象決定,調用函數中的this會指向最後一層調用對象
function foo() {
console.log(this.name);
}
var obj = {
name: "obj",
foo: foo
}
obj.foo();//obj
但是隱式綁定存在着一個隱患(隱式丟失)
var name = "global";
var bar = obj.foo;
bar();//global
雖然bar是obj.foo的一個引用,但是實際上引用的是foo函數本身,此時bar()實際上是變成foo(),應用了默認綁定
另一種隱式丟失的情況出現在參數傳遞中
function doFoo(fn) {
fn();
}
doFoo(obj.foo) //global
因爲參數傳遞時也會發生隱式賦值 fn = obj.foo
3.顯式綁定
function.call(...)
function.apply(...)
這兩個函數區別在於第二部分的參數,具體可以看我之前的博客,現在先不討論這個問題
這兩個函數的作用都是將第一個參數綁定到function中的this上,如果第一個參數是個原始值(String Boolean 或者Number),這個原始值會轉換成對象形式(new String(..)等),這通常被稱爲裝箱
function foo() {
console.log(this.name);
}
var obj = {
name: "obj",
foo: foo
}
foo.call(obj);//obj
然而顯式綁定依然存在着我們之前提出的丟失綁定的問題
但是顯式綁定的的一個變種可以解決這個問題(硬核綁定)
function foo() {
console.log(this.name);
}
var obj = {
name: "obj",
foo: foo
}
var bar = function() {
foo.call(obj);
}
bar(); //obj
這種方式其實就是ES5中的bind()方法
bind方法與call方法的參數形式是一樣的,不同之處在於bind只是返回一個硬綁定了this對象的函數,而call則是綁定了函數中的this對象後執行函數(即使調用call函數的函數本身返回自己,this綁定的對象依然會丟失)
4.new綁定
最後一條this的綁定規則與構造函數有關
JavaScript中的構造函數實際上只是一個使用了new操作符的普通函數
JavaScript實際上不存在所謂的"構造函數",存在的只有對函數的"構造調用"
當函數在new表達式中被調用時,它會初始化新創建的對象
發生的步驟如下
- 創建(構造)一個全新的對象
- 這個新對象會被執行[[Prototype]]連接(不是本篇討論的問題,暫時可以忽略)
-
這個新對象會被綁定到函數調用的this.
- 如果函數沒有返回其他對象,則new表達式會自動返回這個新對象
function foo(a) {
this.a = a;
}
var bar = new foo(2);
console.log(bar.a);//2