淺談js之this對象

  this對象真的是有時讓咱們頭疼,咱們真是分不清它到底指向哪一個做用域,它有時的指向真的是難以想象,它本應該這樣指向卻那樣指向。javascript

雖然有這麼句話,this是調用執行當前代碼的對象的全部者,也就是誰調用它,它就指向誰,那問題來,若是咱們分不清誰調用的它,那怎麼辦呢?html

理論部分java

0X00git

js中的聖經紅寶書和犀牛書對這部分說的不多,可是很精闢;要真正的深入理解書上說的,那麼你對this就一點也不難,可是像我這種菜鳥怎麼可能理解呢???github

紅寶書app

this引用的是函數據以執行的環境對象,this對象是在運行時基於函數執行環境綁定的,在全局中,this等於window,當函數被做爲木個對象的方法調用時,this等於那個對象,不過,因爲匿名函數的執行環境具備全局性,所以,this對象一般指向window,還有就是每一個函數在調用的時候都會自動獲取兩個特殊變量:thisarguments,放在活動對象中,內部在要使用這兩個變量時,只是會在本函數的活動對象中搜索,永遠不會沿着做用域鏈訪問外面的活動對象。ide

犀牛書函數

this對象沒有做用域的限制,嵌套的函數不會從調用它的函數中繼承this,若是嵌套函數做爲方法調用,其this值指向調用它的對象,若是嵌套函數做爲函數調用,其this值不是全局對象(非嚴格模式)就是undefined(嚴格模式);不少人誤覺得調用嵌套函數時this會指向調用外層函數的上下文。this

這就是解釋的。當你真正理解了this後看這些話,你感受他們說的this判斷就是這麼回事頗有感受,可是對於我來講,讀過這些話沒太有感受,不理解。spa

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

聲明如下我說的都是在咱們判斷this對象指向時能夠這麼想,其餘時候你可別這樣想呀!有小部分是不太適合的,那樣說的話;

      我說的都是本身的理解,若是你感受我說的不對,歡迎指正!

      我說的這些例子中有不少是相似的,只是爲了讓咱們加深理解!

0X01

this往大了說無非就是全局中的和函數(方法)中的,只是這函數(方法)中的太過於複雜;

其實能夠大體劃分爲五類:

  1. 全局下中【this】
  2. 函數中調用【foo(foo2(this))】(這裏是指在函數中執行的函數即函數嵌套函數)
  3. 方法調用【obj.foo(this)】(這是是指對象調用函數時)
  4. 構造函數中【new Foo(this)】
  5. apply和call中【foo.apply(obj)】

有時候也很差說是在五種的哪種;只是大體這樣吧;                     參考: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
View Code

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
View Code

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操做符,調用構造函數其實經歷瞭如下四個過程:

  1. 自動建立一個對象
  2. 將構造函數的做用域賦給新對象(所以this就指向了這個新對象)
  3. 執行構造函數中的代碼
  4. 把這個新對象返回出去(隱式的return)

其實就是這樣差很少:

function person() {
    var o = {};
    o.x = 1;
    return o;
}
var people = person();
console.log(people.x);
View Code

 這個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權威指南

相關文章
相關標籤/搜索