JavaScript中的this

MDN|JavaScript this

一、this的指向

1.this是Javascript語言的一個關(guān)鍵字。
它代表函數(shù)運(yùn)行時潭袱,自動生成的一個內(nèi)部對象挪略,只能在函數(shù)內(nèi)部使用历帚。

      function test(){
        this.x = 1;
      }

2.理解這句話:

this的指向在函數(shù)定義的時候是確定不了的滔岳,只有函數(shù)執(zhí)行的時候才能確定this到底指向誰,實際上this的最終指向的是那個調(diào)用它的對象挽牢。

  • 情況1:如果一個函數(shù)中有this谱煤,但是它沒有被上一級的對象所調(diào)用,那么this指向的就是window(嚴(yán)格模式下禽拔,this指向不是window刘离,是undefined)
function a(){
    var user = "via";
    console.log(this.user); //undefined
    console.log(this); //Window
}
a();
  • 情況2:函數(shù)有被上一級的對象所調(diào)用, 則this指向的就是上一級的對象睹栖。
var o = {
    user:"via",
    fn:function(){
        console.log(this.user); //via
    }
}
window.o.fn();
var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //12
        }
    }
}
o.b.fn();
  • 情況3:函數(shù)中包含多個對象硫惕,盡管這個函數(shù)是被最外層的對象所調(diào)用,this指向的也只是它上一級的對象野来。
var o = {
    a:10,
    b:{
        // a:12,
        fn:function(){
            console.log(this.a); //undefined
        }
    }
}
o.b.fn();
  • 特殊:
var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //undefined
            console.log(this); //window
        }
    }
}
var j = o.b.fn;
j();
//函數(shù)fn是被對象b所引用恼除,但是在將fn賦值給變量j的時候并沒有執(zhí)行
//所以最終指向的是window
  • 當(dāng)this碰到return
    如果返回值是一個對象,那么this指向的就是那個返回的對象曼氛,如果返回值不是一個對象那么this還是指向函數(shù)的實例豁辉。
function fn()  
{  
    this.user = 'via';  
    return {};  
}
var a = new fn;  
console.log(a.user); //undefined
function fn()  
{  
    this.user = 'via';  
    return 1;
}
var a = new fn;  
console.log(a.user); //via

特殊:雖然null也是對象,但是在這里this還是指向那個函數(shù)的實例

function fn()  
{  
    this.user = 'via';  
    return null;
}
var a = new fn;  
console.log(a.user); //via

二舀患、call徽级、apply、bind改變this指向

  • 直接看代碼
var a = {
    user:"via",
    fn:function(){
        console.log(this.user);
    }
}
var b = a.fn;
b(); //undefined
a.fn(); //via
b.call(a);//通過在call方法构舟,給第一個參數(shù)添加要把b添加到哪個環(huán)境中灰追,this就會指向那個對象。
          //call還可以添加多個參數(shù)
b.apply(a);//apply也可以有多個參數(shù)狗超,不同的是第二個參數(shù)必須是一個數(shù)組
  • 如果call和apply的第一個參數(shù)寫的是null弹澎,那么this指向的是window對象
var a = {
   user:"via",
   fn:function(){
       console.log(this); //Window
   }
}
var b = a.fn;
b.call(null);//window
b.apply(null);//window
  • bind方法返回的是一個修改過后的函數(shù)。
var a = {
    user:"via",
    fn:function(){
        console.log(this.user);
    }
}
var b = a.fn;
b.bind(a);
//firefox:bound fn()
 length: 0
 name: "bound fn"
 __proto__: function ()
//chrome:? (){
        console.log(this.user);
    }
var a = {
    user:"via",
    fn:function(){
        console.log(this.user); //via
    }
}
var b = a.fn;
var c = b.bind(a);
c();//執(zhí)行函數(shù)
  • 同樣bind也可以有多個參數(shù)努咐,并且參數(shù)可以執(zhí)行的時候再次添加苦蒿,但是要注意的是,參數(shù)是按照形參的順序進(jìn)行的
var a = {
    user:"via",
    fn:function(e,d,f){
        console.log(this.user); //via
        console.log(e,d,f); //10 1 2
    }
}
var b = a.fn;
var c = b.bind(a,10);
c(1,2);

二渗稍、其他指向

  • 構(gòu)造函數(shù)
    通過這個函數(shù)生成一個新對象(object)佩迟。這時,this就指這個新對象竿屹。
function Fn(){
    this.num = 1;
}
var a = new Fn();
console.log(a.num); //1

//a創(chuàng)建了一個Fn的實例并沒有執(zhí)行
//調(diào)用這個函數(shù)Fn的是對象a报强,那么this指向的自然是對象a
  • 存在于一個對象的原型鏈上,那么this指向的是調(diào)用這個方法的對象
var o = {
  f : function(){ 
    return this.a + this.b; 
  }
};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5
  • 作為一個內(nèi)聯(lián)事件處理函數(shù)
    this指向監(jiān)聽器所在的DOM元素:
<button onclick="alert(this.tagName.toLowerCase());">
  Show this
</button>
  • 作為一個DOM事件處理函數(shù)
    this指向觸發(fā)事件的元素(一些瀏覽器在使用非addEventListener的函數(shù)動態(tài)添加監(jiān)聽函數(shù)時不遵守這個約定)拱燃。
// 被調(diào)用時秉溉,將關(guān)聯(lián)的元素變成藍(lán)色
function bluify(e){
  console.log(this === e.currentTarget); // 總是 true

  // 當(dāng) currentTarget 和 target 是同一個對象是為 true
  console.log(this === e.target);        
  this.style.backgroundColor = '#A5D9F3';
}
  • getter或setter的函數(shù)都會把 this 綁定到正在設(shè)置或獲取屬性的對象。
function sum() {
  return this.a + this.b + this.c;
}

var o = {
  a: 1,
  b: 2,
  c: 3,
  get average() {
    return (this.a + this.b + this.c) / 3;
  }
};

Object.defineProperty(o, 'sum', {
    get: sum, enumerable: true, configurable: true});

console.log(o.average, o.sum); //  2, 6

三、在匿名函數(shù),定時器中的函數(shù)setTimeout/setInterval中

function Person() {  
    this.age = 0;  
    setTimeout((function() {
        console.log(this);
    }), 1000);
}

var p = new Person();//window
  • 匿名函數(shù),定時器中的函數(shù),由于沒有默認(rèn)的宿主對象,所以默認(rèn)this指向window
  • 用一個 變量提前把正確的 this引用保存 起來, that = this 或者 ** _this = this** 來保存我們需要的this指針
function Person() {
    var that=this ; 
    that.age = 0;  
    setTimeout((function() {
        console.log(that);
    }).bind(this), 3000);
}

var p = new Person();//1秒后返回構(gòu)造函數(shù)新生成的對象 Person{...}
  • 或用func.bind(this)給回調(diào)函數(shù)直接綁定宿主對象, bind綁定宿主對象后依然返回這個函數(shù)
function Person() {  
    this.age = 0;  
    setTimeout((function() {
        console.log(this);
    }).bind(this), 1000);
}

var p = new Person();//1秒后返回構(gòu)造函數(shù)新生成的對象 Person{...}

四召嘶、箭頭函數(shù)

  • 不綁定this
    箭頭功能不會創(chuàng)建自己的this父晶;它使用封閉執(zhí)行上下文的this值。
  • 在箭頭函數(shù)中弄跌,this是根據(jù)當(dāng)前的詞法作用域來決定的甲喝,就是說,箭頭函數(shù)會繼承外層函數(shù)調(diào)用的this綁定(無論this綁定到什么)铛只。在全局作用域中埠胖,它會綁定到全局對象上。
    (默認(rèn)指向在定義它時所處的對象(宿主對象),而不是執(zhí)行時的對象, 定義它的時候,可能環(huán)境是window)
var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true

注意:如果將thisArg傳遞給call淳玩、bind押袍、或者apply,它將被忽略(thisArg即傳入三個函數(shù)中的第一個參數(shù))凯肋。仍可以為調(diào)用添加參數(shù)谊惭,不過第一個參數(shù)應(yīng)該設(shè)置為null。

  • 與普通函數(shù)對比
    var obj={  
        num:3,  
        fn:function(){  
            setTimeout(function(){  
                console.log(this.num);  
              //this出現(xiàn)在全局函數(shù)setTImeout()中的匿名函數(shù)里
             //并沒有某個對象進(jìn)行顯示調(diào)用侮东,所以this指向window對象 
            });  
        }  
    }  
    obj.fn();//undefined 
    var obj1={  
        num:4,  
        fn:function(){  
            setTimeout(() => {  
                console.log(this.num);  //this指向函數(shù)的宿主對象了 
            });  
        }  
    }  
    obj1.fn();//4  
  • 多層嵌套的箭頭函數(shù)
    var obj1={  
        num:4,  
        fn:function(){  
            var f=() => {    //object圈盔,也就是指obj1  
                console.log(this);  
                setTimeout(() => {  
                    console.log(this);//object,也就是指obj1  
                });  
            }  
            f();  
        }  
    }  
    obj1.fn();  

改動一處箭頭函數(shù)

    var obj1={  
        num:4,  
        fn:function(){  
            var f=function(){      
                console.log(this); 
              //函數(shù)f定義后并沒有對象調(diào)用悄雅,this直接綁定到最外層的window對象  
                setTimeout(() => {  
                    console.log(this);
                //外層this綁定到了window,內(nèi)層也相當(dāng)于定義在window層(全局環(huán)境)  
                });  
            }  
            f();  
        }  
    }  
    obj1.fn();  
    var obj1={  
        num:4,  
        fn:function(){  
            var f=() => {      
                console.log(this); 
               //object,f()定義在obj1對象中驱敲,this就指向obj1,這是箭頭函數(shù)this指向的關(guān)鍵  
                setTimeout(function() {  
                    console.log(this);
                     //window,非箭頭函數(shù)的情況下還是要看宿主對象是誰
                     //如果沒有被對象調(diào)用宽闲,函數(shù)體中的this就綁定的window上  
                });  
            }  
            f();  
        }  
    }  
    obj1.fn();  
  • 1.箭頭函數(shù)的this綁定看的是this所在的函數(shù)定義在哪個對象下众眨,綁定到哪個對象則this就指向哪個對象
  • 2.如果有對象嵌套的情況,則this綁定到最近的一層對象上
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末容诬,一起剝皮案震驚了整個濱河市娩梨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌览徒,老刑警劉巖狈定,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異习蓬,居然都是意外死亡纽什,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門躲叼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芦缰,“玉大人,你說我怎么就攤上這事枫慷∪美伲” “怎么了包斑?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長涕俗。 經(jīng)常有香客問我,道長神帅,這世上最難降的妖魔是什么再姑? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮找御,結(jié)果婚禮上元镀,老公的妹妹穿的比我還像新娘。我一直安慰自己霎桅,他們只是感情好栖疑,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著滔驶,像睡著了一般遇革。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上揭糕,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天萝快,我揣著相機(jī)與錄音,去河邊找鬼著角。 笑死揪漩,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的吏口。 我是一名探鬼主播奄容,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼产徊!你這毒婦竟也來了昂勒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤舟铜,失蹤者是張志新(化名)和其女友劉穎叁怪,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體深滚,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡奕谭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了痴荐。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片血柳。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖生兆,靈堂內(nèi)的尸體忽然破棺而出难捌,到底是詐尸還是另有隱情膝宁,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布根吁,位于F島的核電站员淫,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏击敌。R本人自食惡果不足惜介返,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望沃斤。 院中可真熱鬧圣蝎,春花似錦、人聲如沸衡瓶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哮针。三九已至关面,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間十厢,已是汗流浹背缭裆。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留寿烟,地道東北人澈驼。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像筛武,于是被迫代替她去往敵國和親缝其。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 導(dǎo)語 不得不說徘六,作為一名初級的前端開發(fā)者内边,this關(guān)鍵字這個問題對于我來說一直是一個痛點,什么是this待锈?什么是函...
    Nicole_tiny閱讀 530評論 0 4
  • 1.函數(shù)調(diào)用棧和調(diào)用位置 在函數(shù)執(zhí)行的時候漠其,會有一個活動記錄(也叫執(zhí)行上下文)來記錄函數(shù)的調(diào)用順序,這個就是函數(shù)調(diào)...
    lightNate閱讀 525評論 1 14
  • 作者:yuanzm原文地址:http://segmentfault.com/a/1190000002640298 ...
    IT程序獅閱讀 824評論 0 22
  • 不論是面向?qū)ο蟾鸵簦€是基于對象的語言和屎,都會有this,我更喜歡叫他this指針春瞬,如果你不理解指針柴信,認(rèn)為它是個引用也無...
    faremax閱讀 680評論 2 1
  • 當(dāng)有人問起你JavaScript有什么特點的時候,你可能立馬就想到了單線程宽气、事件驅(qū)動随常、面向?qū)ο蟮纫欢言~語潜沦,但是如果...
    yo_yo_閱讀 367評論 0 1