this對象真的是有時讓咱們頭疼,咱們真是分不清它到底指向哪一個做用域,它有時的指向真的是難以想象,它本應該這樣指向卻那樣指向。javascript
雖然有這麼句話,this是調用執行當前代碼的對象的全部者,也就是誰調用它,它就指向誰,那問題來,若是咱們分不清誰調用的它,那怎麼辦呢?html
理論部分:java
0X00:git
js中的聖經紅寶書和犀牛書對這部分說的不多,可是很精闢;要真正的深入理解書上說的,那麼你對this就一點也不難,可是像我這種菜鳥怎麼可能理解呢???github
紅寶書:app
this引用的是函數據以執行的環境對象,this對象是在運行時基於函數執行環境綁定的,在全局中,this等於window,當函數被做爲木個對象的方法調用時,this等於那個對象,不過,因爲匿名函數的執行環境具備全局性,所以,this對象一般指向window,還有就是每一個函數在調用的時候都會自動獲取兩個特殊變量:this和arguments,放在活動對象中,內部在要使用這兩個變量時,只是會在本函數的活動對象中搜索,永遠不會沿着做用域鏈訪問外面的活動對象。ide
犀牛書:函數
this對象沒有做用域的限制,嵌套的函數不會從調用它的函數中繼承this,若是嵌套函數做爲方法調用,其this值指向調用它的對象,若是嵌套函數做爲函數調用,其this值不是全局對象(非嚴格模式)就是undefined(嚴格模式);不少人誤覺得調用嵌套函數時this會指向調用外層函數的上下文。this
這就是解釋的。當你真正理解了this後看這些話,你感受他們說的this判斷就是這麼回事頗有感受,可是對於我來講,讀過這些話沒太有感受,不理解。spa
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
聲明:如下我說的都是在咱們判斷this對象指向時能夠這麼想,其餘時候你可別這樣想呀!有小部分是不太適合的,那樣說的話;
我說的都是本身的理解,若是你感受我說的不對,歡迎指正!
我說的這些例子中有不少是相似的,只是爲了讓咱們加深理解!
0X01:
this往大了說無非就是全局中的和函數(方法)中的,只是這函數(方法)中的太過於複雜;
其實能夠大體劃分爲五類:
有時候也很差說是在五種的哪種;只是大體這樣吧; 參考:http://bonsaiden.github.io/JavaScript-Garden/zh/#function.this
實戰部分:
0x00:在全局中的狀況
全局中:
0x01:
var a = 1; console.log(this);//window console.log(this.a);//1
這就是全局中的this它是指向window對象的,這種狀況很簡單
0x01:函數調用中的
若是一個函數的調用者是一個函數,那麼那個被調用的函數中的this是指向window的
咱們就是在對象的方法裏調用函數,有時讓咱們分不清,其實在this眼裏,全部的函數都是跟普通函數差很少;
在javascript語言精粹上說,在此模式中this被綁定到全局對象,這是語言設計上的一個錯誤。
001:setTimeout和setInterval中的this
這個是要單獨拿出來的,他們其實都是來自window的方法,這兩個函數不論是在哪裏調用,;其執行上下文環境是window對象下的環境;
var num = 1; var obj = { num:2, show:function() { console.log(this.num); }, showNum:function() { setTimeout(this.show,1000); } }; obj.showNum();//1
參數中的this是傳遞引用的過來的,是和showNum中的this是同樣的,其實這個this不是重點,在這裏,show方法裏面的this纔是重點
個人理解是當程序執行到setTimeout的時候經過this.show獲取對obj對象中show函數引用,show函數裏面的this應該指向誰呢?(你不要誤認爲這個方法定義在obj中就和obj有關係(確實有關係,可是在this對象看來:函數定義在哪裏都同樣,在它看來大家都是一個個孤立的函數,就看你是在哪裏調用的),你就記住這句話:在this對象看來:函數無論定義在哪裏,都是同樣的,沒有區別,無論你是在對象中仍是函數中,仍是全局中的,都是同樣的,我就是看你在哪裏調用了,this是和javascript中執行環境有關,而非聲明環境有關),
,不要認爲show函數是obj的,就和obj有關係,這裏就是想當於setTimeout(function(){console.log(this.num)},1000);其實這就是函數中嵌套函數,因此裏面的this指向window;若是你感受setTimeout有特別不和其餘函數同樣,你就看下面的,同樣的,只不過這個是普通函數:
var num = 2; var obj = { num:1, foo2:function() { function foo3(a) { console.log(this);//window console.log(a);//1 } foo3(this.num);//this =>obj } } obj.foo2();
在調用foo3時他參數this就是obj,跟setTimeout中的是同樣的;它裏面的this也是window,這就是foo3是函數調用的,
002:
var x = 2; var obj = { x:1, a:function () { var x = 3; var b = function () { console.log(this.x); }; b(); } } obj.a();//2
這個和上面那個例子差很少,就是函數中嵌套函數的狀況,必定是指向window了
003,簡單的:
function foo() { function bar() { alert(this); } bar(); } foo();//window
0x02:方法中的調用
必定指向調用它的那個對象
001:
var num = 1; function foo() { console.log(this.num); } foo();//1
這其實就是window對象下的foo()方法的調用 ==》window.foo();只是在全局下能夠省去罷了;
002:
var obj = { num:1, foo:function() { console.log(this.num); } } obj.foo();//1
003:
var obj1 = { num:1, showNum1:function() { console.log(this.num); } }; var obj2 = { num:2, showNum2:obj1.showNum1 } obj2.showNum2();//2
其實obj2等價與這樣:
var obj2 = { num:2, showNum2:function(){ console.log(this.num); } }
只不過這個函數我是引用的obj1中的showNum2函數罷了,這樣看你就知道了,再次說明了我說setTimeout時所說的,只不過咱們showNum2:obj1.showNum1這樣用就給咱們一種感受,它就是跟obj1有關係,其實在this看來沒有關係,this就是個有奶即是孃的東西,它無論哪一個娘生的它,誰是它親孃(在哪一個地方聲明(定義)的它),只要給的奶喝,它就認誰爲娘(誰執行調用的它);你必定要拋開聲明地方不一樣,對你的影響;
004:
var x= 2; var obj = { x:1, fn:function() { alert(this.x); } }; // obj.fn(); var test = obj.fn; test();//2
也是那種狀況,
等價與
var test = function(){ alert(this.x); } test();//2
005:
function foo() { alert(this.bar); } var x = {bar: 10}; var y = {bar: 20}; x.test = foo; y.test = foo; x.test(); // 10 y.test(); // 20
006:
var x = 10; var obj = { foo:function() { alert(this.x); }, x:20 }; with(obj) { foo();//20 }
調用foo時就是至關於obj.foo();
007:
var x = 3; var foo = { x:2, baz:{ x:1, bar:function() { return this.x; } } } var go = foo.baz.bar; console.log(go());//3 console.log(foo.baz.bar());//1
這就是變量go引用了函數function(){return this.x};這個就是foo.baz調用了bar()函數因此this指向調用者foo.baz這個對象
008:
function Foo() {} Foo.prototype.method = function() {console.log(this)}; function Bar() {} Bar.prototype = Foo.prototype; var obj = new Bar(); obj.method();//Bar
0x03:構造函數中
function Person() { console.log(this); this.x = 1; } var people = new Person(); console.log(people.x);//10
上面沒有顯式的建立對象;直接將屬性賦值給this對象;沒有return語句;
其實在你使用new操做符,調用構造函數其實經歷瞭如下四個過程:
其實就是這樣差很少:
function person() { var o = {}; o.x = 1; return o; } var people = person(); console.log(people.x);
這個this是有用處的,它可使每一個new實例化的對象都有屬於本身的屬性,而不全都是從原型中繼承而來的。
0x04:apply和call方法中
他們都是在特定做用域中調用函數,實際上等於設置了函數體內的this對象的值,第一個參數在ES3或非嚴格模式中,傳入的的null和undefined都會被全局對象代替,其餘的原始值則會被相應的包裝對象所代替,在嚴格模式下,第一個實參是null或undefined時,裏面的this就是null或者是undefined,
001:
function f() { console.log(this.x + " " + this.y); } var obj = { x:1, y:2 } f.call(obj);//1 2
這裏的this就是obj
002:
function show() { console.log(this); function test() { console.log(this); } test(); } show.call({x:1});//{X:1},window
這裏就是首先因爲call方法因此改變了做用域,show()函數的this指向了{x:1},test()屬於函數調用函數的狀況因此是window對象;
上面說的都是javascript語言中this;
如今說說DOM對象中的this
001.
一種是DOM0級事件綁定中的this,
obj.onclick = function () { console.log(this);//obj }
上面說了這麼多你,你在看這裏爲何這個this是obj你知道了嗎?由於當你觸發事件的時候,是obj對象就會檢測它的onclick屬性有沒有綁定函數,若是綁定了就調用。
002.
DOM2級中的
先來個這樣的:
<script type="text/javascript"> var x = 2; var obj = { x:1, fn:function(f) { f(); } } obj.fn(function(){console.log(this.x);});//2 </script>
它是會顯示2的,也就是說這個this是window,和上面我羅嗦了半天的函數調用的狀況,函數中調用函數
可是你看這裏:
var x = 2; var test = document.getElementById("test"); test.x = 1; test.addEventListener('click',function() { console.log(this.x);//1 console.log(this);//test對象 });
這是怎麼回事???要是按照上面的來應該是window對象呀,這就是addEventListener方法的特別之處,它不是不一樣的函數呀,簡單說這個函數的做用就是把第二個參數的的函數,綁定在調用它的那個對象(這裏是test)下的,有跟addEventListener的第一個參數的名字相同的屬性名下。就相似這樣:
test = { //這裏是不少的屬性名 //..... //...... click:function(){ console.log(this); } }
這個函數大致就是這個做用;
而IE的attachEvent就跟上面說的就差很少了,它的this是window;
不寫了就寫這麼多吧。總結就是,this是和執行環境有關,不是和聲明函數有關,在你用this的時候要當心點,實在不肯定是什麼,你就alert一下,不就知道了
下面這些是個人蔘考,個人不少不少例子就是從他們那裏的,要否則那麼多狀況我怎麼一時半會也想不出出來呀,他們寫的這些都是精化呀,若是你感受我寫的把你搞暈了的話,尚未明白的話,我建議你看看這些,我相信在你看明白這些後你就對this有本身的理解和認識;
javascript祕密花園:http://bonsaiden.github.io/JavaScript-Garden/zh/#function.this
大叔的:http://www.cnblogs.com/TomXu/archive/2012/01/17/2310479.html
大額_skylar:http://www.cnblogs.com/skylar/p/4042663.html
http://www.cnblogs.com/justany/archive/2012/11/01/the_keyword_this_in_javascript.html
http://www.cnblogs.com/KevinYang/archive/2009/07/14/1522915.html
http://www.cnblogs.com/rush/archive/2012/07/31/2617429.html
javascript高級程序設計
javascript權威指南