什麼是函數?
在js中函數是對象。
invocation(調用)
調用一個函數時,函數接受兩個附加的參數:this和arguments。參數this的初始化方式取決於調用的模式。一共有四種調用模式:
方法調用模式(the method invocation pattern)又稱爲隱式綁定
當一個函數被保存爲一個對象的屬性時,被稱爲‘方法’。當一個方法被調用時,this被綁定到該對象。
function foo() { console.log( this.a ); }
var obj = { a: 2, foo: foo };
obj.foo(); // 2
對象屬性引用鏈中只有最頂層或者說最後一層會影響調用位置。舉例來說:
function foo() { console.log( this.a ); }
var obj2 = { a: 42, foo: foo };
var obj1 = { a: 2, obj2: obj2 };
obj1.obj2.foo(); // 42
tips:隱式丟失:
function foo() { console.log( this.a ); }
var obj = { a: 2, foo: foo };
var bar = obj.foo; // 函數別名!
var a = "oops, global"; // a 是全局對象的屬性
bar(); // "oops, global
這時候的bar只是引用了foo函數本身,因此此時的 bar() 其實是一個不帶任何修飾的函數調用,因此應用了默認綁定。
函數調用模式(the function invocation pattern)又稱爲 默認調用
當函數並未一個對象的屬性時,它被當作一個函數來調用。
function foo() {
console.log( this.a );
}
var a = 2;
foo(); // 2
函數調用時應用了 this 的默認綁定,因此 this 指向全局對象。雖然 this 的綁定規則完全取決於調用位置,但是隻 有 foo() 運行在非 strict mode 下時,默認綁定才能綁定到全局對象
function foo() { "use strict";
console.log( this.a ); }
var a = 2;
foo(); // TypeError: this is undefine
構造器調用模式
如果函數傾向於和 new 關鍵詞一塊使用,則我們稱這個函數是 構造函數。 在函數內部,this 指向新創建的對象。
var Quo=function (string){
this.status=string;
}
//給Quo的所有實例提供一個名爲get_status的公共方法
Quo.prototype.get_status=function(){
return this.status;
};
var myQuo=new Quo('confused');
document.writeln(myQuo.get_status());//confused
or
function foo(a) { this.a = a; }
var bar = new foo(2); console.log( bar.a ); // 2
apply or call 調用模式(顯式綁定)
這兩個方法是如何工作的呢?它們的第一個參數是一個對象,它們會把這個對象綁定到 this,接着在調用函數時指定這個 this。因爲你可以直接指定 this 的綁定對象,因此我 們稱之爲顯式綁定。
function foo() { console.log( this.a ); }
var obj = { a:2 };
foo.call( obj ); // 2
從 this 綁定的角度來說,call(…) 和 apply(…) 是一樣的,它們的區別體現 在其他的參數上,但是現在我們不用考慮這些。
總結:
- 函數是否在 new 中調用(new 綁定)?如果是的話 this 綁定的是新創建的對象。 var bar = new foo()
- 函數是否通過 call、apply(顯式綁定)或者硬綁定調用?如果是的話,this 綁定的是 指定的對象。 var bar = foo.call(obj2)
- 函數是否在某個上下文對象中調用(隱式綁定)?如果是的話,this 綁定的是那個上 下文對象。 var bar = obj1.foo()
- 如果都不是的話,使用默認綁定。如果在嚴格模式下,就綁定到 undefined,否則綁定到 全局對象。 var bar = foo()