概述
在絕大多數(shù)情況下,函數(shù)的調(diào)用方式?jīng)Q定了this
的值吩坝。在絕大多數(shù)情況下控轿,函數(shù)的調(diào)用方式?jīng)Q定了this
的值。this
不能在執(zhí)行期間被賦值宿礁,并且在每次函數(shù)被調(diào)用時this
的值也可能會不同案铺。
this
的指向在函數(shù)定義的時候是確定不了的,只有函數(shù)執(zhí)行的時候才能確定this到底指向誰梆靖,實(shí)際上this的最終指向的是那個調(diào)用它的對象
this 中的四種綁定方式 ?
一 默認(rèn)綁定
console.log(this === window);
console.log(this.document === document);
this.a = 91;
console.log(window.a);
全局環(huán)境中控汉,this默認(rèn)綁定到window。
例子:
var a = 0;
function foo(){
(function test(){
console.log(this.a);
})()
};
var obj = {
a : 2,
foo:foo
}
obj.foo();
等價于上例
var a = 0;
var obj = {
a : 2,
foo:function(){
function test(){
console.log(this.a);
}
test();
}
}
obj.foo();//0
函數(shù)獨(dú)立調(diào)用時返吻,this默認(rèn)綁定到window姑子。
(function () {
console.log(this === window); // true
})();
function foo(){
console.log(this === window);
}
foo();
二 隱式綁定
function foo() {
console.log( this.a )
}
var obj2 = {
a: 42,
foo: foo
}
var obj1 = {
a: 2,
obj2: obj2
}
obj1.obj2.foo();
結(jié)合上面的例子,this的指向可以總結(jié)為一下三種情況测僵。
情況1:如果一個函數(shù)中有this
壁酬,但是它沒有被上一級的對象所調(diào)用,那么this
指向的就是window
恨课,在js的嚴(yán)格版中this
指向的不是window
舆乔,而是undefined
。
情況2:如果一個函數(shù)中有this
剂公,這個函數(shù)有被上一級的對象所調(diào)用希俩,那么this
指向的就是上一級的對象。
情況3:如果一個函數(shù)中有this
纲辽,這個函數(shù)中包含多個對象颜武,盡管這個函數(shù)是被最外層的對象所調(diào)用,this
指向的也只是它上一級的對象拖吼。
隱式丟失
var o = {
a:10,
b: {
a:12,
fn:function(){
console.log(this.a);
console.log(this);
}
}
}
var j = o.b.fn;
j();
函數(shù)別名的情況
賦值操作和調(diào)用不是同一個概念鳞上,上面說的 this是指向上一級調(diào)用它的對象,跟賦值操作沒有上面關(guān)系吊档。例子中雖然函數(shù) fn 是被對象b 所引用篙议,但是在將 fn 賦值給變量 j 的時候并沒有執(zhí)行所以最終指向的是 window。
var a = 2;
function foo() {
console.log( this.a );
}
var o = { a: 3, foo: foo };
var p = { a: 4 };
o.foo();
(p.foo = o.foo)();
間接引用的情況
等價于函數(shù)別名的情況。
如果要輸出 4 鬼贱,該怎么做移怯?
var a = 2;
function foo() {
console.log( this.a );
}
var o = { a: 3, foo: foo };
var p = { a: 4 };
o.foo();
p.foo = o.foo;
p.foo();
三 顯示綁定
就是給this指定值,如:new这难,call, apply, bind綁定等
1)call 和 apply 綁定
function foo( something ) {
console.log( this.a, something)
return this.a + something
}
var obj = {
a: 2
}
var bar = function() {
return foo.apply( obj, arguments)
}
var b = bar(3);
console.log(b);
類型轉(zhuǎn)換
function bar() {
console.log(Object.prototype.toString.call(this));
}
bar.call(7);
使用 call
和apply
函數(shù)時要注意舟误,如果傳遞給this
的值不是一個對象,JS會嘗試使用內(nèi)部的ToObject
操作將其轉(zhuǎn)化為對象姻乓。因此嵌溢,如果傳遞的值是一個原始值比如 7 ,那么就會使用相關(guān)構(gòu)造函數(shù)將它轉(zhuǎn)換為對象蹋岩,所以原始值7會被轉(zhuǎn)換為對象赖草,像new Number(7)
這樣。
2) bind 綁定
var module = {
x: 42,
getX: function() {
return this.x;
}
}
var unboundGetX = module.getX;
console.log(unboundGetX());
var boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
調(diào)用f.bind(someObject)
會創(chuàng)建一個與f
具有相同函數(shù)體和作用域的函數(shù)星澳,但是在這個新函數(shù)中疚顷,this
將永久地被綁定到了bind
的第一個參數(shù),無論這個函數(shù)是如何被調(diào)用的禁偎。返回由指定的this
值和初始化參數(shù)改造的原函數(shù)拷貝
function foo( something ) {
console.log( this.a, something)
return this.a + something
}
var obj = {
a: 2
}
var bar = foo.bind(obj)
var b = bar(3);
console.log(b);
注意 bind指生效一次
3) new 綁定
在傳統(tǒng)面向類的語言中腿堤,使用new
初始化類的時候會調(diào)用類中的構(gòu)造函數(shù),但是JS中new
的機(jī)制實(shí)際上和面向類和語言完全不同如暖。
使用new
來調(diào)用函數(shù)笆檀,或者說發(fā)生構(gòu)造函數(shù)調(diào)用時,會自動執(zhí)行下面的操作:
創(chuàng)建(或者說構(gòu)造)一個全新的對象
這個新對象會被執(zhí)行
[[Prototype]]
連接-
這個新對象會綁定到函數(shù)調(diào)用的
this
function fn() { this.a = 2; } var test = new fn(); console.log(test);
當(dāng) this 遇到 return 時
在構(gòu)造函數(shù)中使用this
分為兩種情況
function fn()
{
this.user = 'zhong';
return undefined;
}
var a = new fn;
console.log(a);
函數(shù)當(dāng)作構(gòu)造函數(shù)使用且函數(shù)內(nèi)沒有返回值盒至,或返回值是5種基本型(Undefined
類型酗洒、Null
類型、Boolean
類型枷遂、Number
類型樱衷、String
類型)之一,指向?qū)嵗蟮膶ο?/p>
function fn()
{
this.user = 'zhong';
return [1,2,3,4];
}
var a = new fn;
console.log(a);
函數(shù)當(dāng)作構(gòu)造函數(shù)使用且有return值酒唉,返回是數(shù)組矩桂、對象等,this指向返回值
function C2() {
this.a = 1;
return {
a: 2
};
}
o = new C2();
console.log(o);
Reference