javascript中關於this的理解


首先看一下這幾個定義

  • this對象是在運行時基於函數的執行環境綁定的:在全局函數中,this等於window,而當函數被視為某個對象的方法調用時,this等於那個對象。
    不過,匿名函數的執行環境具有全局性,因此其this對象通常指向window.

  • 每個函數在被調用的過程中都會自動取得兩個特殊變量:this和arguemtns。內部函數在搜索這兩個變量的時候,只會搜索到其活動對象為止,因此永遠不可能訪問外部函數中的這兩個變量。

  • this實際上是在函數被調用時發生的綁定,它指向什么完全取決於函數在哪里被調用。

首先,先排除幾個錯誤的認知:
1、this對象是指向自身的。
function foo(num){
console.log(num);
this.count++;
}
foo.count=0;
for(var i=0;i<5;i++){
foo(i)
};
console.log(foo.count); //0
通過這個實例可以看出,count雖然被設置為了foo的屬性。但是這里的this並不是指向foo自身的,因此當輸出foo.count值的時候,其依然是0.

2、this是指向自身的詞法作用域的,也可以簡單理解成對於變量對象的引用吧。
function foo(){
var a=2;
console.log(this.a);
}
foo(); //undefined;
我們在foo函數的作用域內定義了a的值為2,然而當我們輸出a的值的時候卻可以的到undefined,因此這樣的理解也是不對的。

實際上,this是在函數被調用時發生的綁定,它指向什么完全取決於在哪里調用。
所以說,我們的第一步就是判斷函數的調用位置。

 function baz(){
       //當前調用棧是:baz
       //因此,當前的調用位置是全局作用域
       console.log('baz');
       bar();//bar的調用位置
    }
function bar(){
   //當前調用棧是baz->bar
   //因此調用位置是在baz中
   console.log('bar');
   foo();//<-foo的調用位置

}
function foo(){
   //目前調用棧是baz->bar->foo
   //因此,當前調用位置是在bar中
   console.log('foo')

}
baz();//<--baz的調用位置

分析出了他們的調用位置之后,接下來就是要判斷它是應用於哪種綁定規則的。
1、默認綁定 獨立函數調用-指向全局
var a=2;
function foo(){
console.log(this.a);
}
foo(); //2
這個例子中,函數的調用位置是全局環境,所以其指向全局即等於window(注意這是在非嚴格模式下)
var a=2;
function foo(){
'use strict';
console.log(this.a);
}
foo(); //undefined
這時,由於嚴格模式的原因將會輸出undefined;
var a=100;
function foo(){
var a='foo中的a';
bar();
}
function bar(){
console.log(this.a);
}
foo();//100
由調用位置決定的另外一個示例。

2、隱式綁定 調用位置是否有上下文對象,或者說是否被某個對象擁有或者包含。
function foo(){
console.log(this.a);
}
var obj={
a:2,
foo:foo
}
obj.foo(); //2
當函數引用有上下文對象時,隱式綁定規則會把函數調用中的this綁定到這個上下文對象中。當然,也有一些隱式綁定的函數丟失綁定對象的問題,例如:
var a='全局中的a';
function foo(){
console.log(this.a);
}
var obj={
a:2,
foo:foo
}
var s=obj.foo;
s(); //全局中的a;
s只是obj.foo的一個引用,而在當s調用的時候已經沒有了上下文對象,因此將會默認綁定,從而輸出‘全局中的a’
還有一種情況:
var a='全局中的a';
function s(fn){
fn();<--調用位置
}
function foo(){
console.log(this.a);
}
var obj={
a:2,
foo:foo
}
s(obj.foo);
fn只是引用了obj.foo,而在obj.foo的調用位置沒有任何特殊綁定,所以是默認綁定指向全局。

3、顯式綁定 用call/apply方法。
function foo(){
console.log(this.a);
}
var obj={
a:'董志強',
foo:foo
}
foo.call(obj);
//通過foo.call(..),我們可以在調用foo時強制把他的this綁定到obj上。

4、new綁定
1創建一個新對象
2這個對象會被執行[proto]連接
3這個新對象會綁定到函數調用的this.
4如果函數沒有返回其他對象,那么new表達式中的函數會自動返回這個新對象。
function foo(a){
this.a=a;
}
var b=new foo(2);
console.log(bar.a);//2

大概就是這樣子的吧,判斷出具體的位置之后,再判斷綁定方式,這樣就可以判斷出this的指向了。也有一些例外情況,例如foo.call(null)或者foo.apply(undefined)的情況,在沒有其他綁定的情況下,這時foo函數里面的this是指向全局的。

這時你會發現是不是好多問題都理解更深刻了,像下面,.
function Person(name,age){
this.name='dong';
this.age=29
}
Person.prototype.z=2;

var person=new Person();
alert(person.z);//2
alert(person.name);//'dong'
都知道,person.z是person對象沿着原型鏈向上查找得到的,因為Person.prototype屬性里面有z這個屬性。
而對於name和age來說他們,則是new綁定,this會指向當前new的對象,所以相當於自身創建了name和age這兩個屬性,而不是向上查找得到的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM