this深入理解

js中this指向有幾種情況

  1. 全局環(huán)境
  2. 函數(shù)調(diào)用
  3. 構(gòu)造調(diào)用
  4. apply柜砾、call轩拨、bind綁定
  5. 箭頭函數(shù)

全局環(huán)境

在瀏覽器中践瓷,無(wú)論是否在嚴(yán)格模式下,在全局執(zhí)行環(huán)境中(在任何函數(shù)體外部)this 都指向全局對(duì)象亡蓉。
在Nodejs環(huán)境晕翠,在全局執(zhí)行環(huán)境中,this指向module.exports砍濒。

函數(shù)調(diào)用

分析一般函數(shù)調(diào)用時(shí)this的指向淋肾,需要先引入引用類型的定義。

引用類型

A Reference is a resolved name or property binding. A Reference consists of three components, the base value, the referenced name and the Boolean valued strict reference flag. The base value is either undefined, an Object, a Boolean, a String, a Symbol, a Number, or an Environment Record (8.1.1). A base value of undefined indicates that the Reference could not be resolved to a binding. The referenced name is a String or Symbol value.——ES2015 6.2.3 The Reference Specification Type

引用類型是一個(gè)ES規(guī)范定義的抽象類型爸邢,是為了解釋delete樊卓、typeof等概念使用,并非js語(yǔ)言中的類型杠河。引用類型由3部分組成:

  1. base value碌尔,可能是undefined浇辜、object、boolean唾戚、string柳洋、symbol、number或一個(gè)環(huán)境記錄叹坦。是這個(gè)引用對(duì)應(yīng)的屬性所處的上下文熊镣。
  2. referenced name,即引用對(duì)應(yīng)的屬性的名募书。
  3. strict reference flag绪囱,標(biāo)記是否處于嚴(yán)格模式下。
GetValue

ES定義的一個(gè)抽象方法锐膜,用于獲取引用類型真實(shí)的值毕箍。

在解釋相關(guān)概念后回到主題,普通的函數(shù)調(diào)用道盏,this是根據(jù)函數(shù)調(diào)用操作符【(...)】左邊的值決定的而柑,如果左邊的是引用類型的值,則this指向該引用類型的base荷逞。若非引用類型媒咳,則為undefined。

例如:

'use strict'
var x = 2;
var foo = {
    x : 1,
    bar: function () {
        console.log(this.x);
    }
};

foo.bar(); //1
(foo.bar = foo.bar)(); //Uncaught TypeError: Cannot read property 'x' of undefined  
//ps.如果沒(méi)有啟用嚴(yán)格模式种远,this為undefined時(shí)涩澡,會(huì)指向全局對(duì)象,則會(huì)輸出2

由于foo.bar = foo.bar采用了賦值操作坠敷,此時(shí)返回內(nèi)容為引用類型的真實(shí)值妙同,所以返回的并非引用類型,此時(shí)this為undefined膝迎。

構(gòu)造調(diào)用

當(dāng)一個(gè)函數(shù)被使用 new 操作符進(jìn)行調(diào)用時(shí)稱為構(gòu)造調(diào)用時(shí)粥帚,在進(jìn)行構(gòu)造調(diào)用時(shí),函數(shù)內(nèi)部的this綁定到正在構(gòu)造的新對(duì)象上限次。new相關(guān)內(nèi)容會(huì)在后續(xù)文章中詳細(xì)寫芒涡。

apply、call卖漫、bind綁定

使用apply费尽,call方法調(diào)用函數(shù)時(shí),this將綁定到方法的第一個(gè)參數(shù)羊始。例如:

var x = {
    a: 1
}

function test() {
    console.log(this.a);
}

test.apply(x); // 1 使用apply調(diào)用時(shí)旱幼,this.綁定到x上了
test.call(x); // 1
test(); //undefined

bind方法會(huì)創(chuàng)建一個(gè)新的函數(shù),新函數(shù)中的bind綁定到bind方法的第一個(gè)參數(shù)突委。bind創(chuàng)建的新函數(shù)不能再被bind進(jìn)行綁定速警,也不會(huì)被apply叹誉、call修改。bind創(chuàng)建的新函數(shù)在進(jìn)行構(gòu)造調(diào)用時(shí)會(huì)改變成指向新創(chuàng)建的對(duì)象闷旧。例如:

var x = {
    foo: 1
}

var y = {
    foo: 2
}

var z = {
    foo: 3
}

function test() {
    console.log(this.foo);
}

var a = test.bind(x);
a();//1 使用bind進(jìn)行綁定

var b = a.bind(y);
b();//1 bind綁定創(chuàng)建的函數(shù)不能被二次綁定,this不再改變
a.call(y);//1 也不會(huì)因?yàn)閍pply钧唐、call調(diào)用改變this

new a(); // undefined 但是能被 new 操作符改變

var c = test.bind(z);
c();//3

箭頭函數(shù)

箭頭函數(shù)的this時(shí)根據(jù)詞法作用域的忙灼,this指向該函數(shù)創(chuàng)建時(shí)的環(huán)境。箭頭函數(shù)沒(méi)有進(jìn)行this綁定钝侠,在箭頭函數(shù)中使用this该园,相當(dāng)于尋找外部環(huán)境的this。此時(shí)this函數(shù)尋值跟普通變量尋值一樣帅韧,會(huì)在作用域鏈中逐層尋找里初。因?yàn)榧^函數(shù)沒(méi)有自己的this,所以有以下幾個(gè)特點(diǎn):

  1. 不能進(jìn)行構(gòu)造調(diào)用忽舟,如:
function foo() {        
}

 var bar = ()=>{
 }
   
console.log(new foo()); // foo {}
console.log(new bar());// Uncaught TypeError: bar is not a constructor
  1. 不能通過(guò)apply双妨、bind、call直接改變箭頭函數(shù)中this
  2. 改變所在作用域中的this的同時(shí)會(huì)改變箭頭函數(shù)中的this

例如:

var x = 10;
var test1 = {
     x : 20,
     y : function(){
         return ()=>{
             console.log(this.x);
         }
     },
     z : function(){
         return function(){
             console.log(this.x);
         }
     }
}

var test2 = { x : 30};
var test3 = { x : 40};

test2.y = test1.y();
test2.z = test1.z();

test2.y(); // 20 因?yàn)榧^函數(shù)的this是在創(chuàng)建的時(shí)候確定的詞法作用域叮阅,實(shí)際上在test1.y()的時(shí)候就確定了刁品,不會(huì)在代碼執(zhí)行時(shí)動(dòng)態(tài)改變
test2.z();// 30 普通函數(shù)調(diào)用的this是動(dòng)態(tài)作用域的,由于z的base是test2的環(huán)境記錄浩姥,所以取到的是test2的x

test2.y.call(test3);//20 箭頭函數(shù)沒(méi)有自己的this挑随,所以不會(huì)被call改變
test2.z.call(test3);//40 普通函數(shù)會(huì)被call改變

test1.y.call(test2)();//30 箭頭函數(shù)在call的時(shí)候創(chuàng)建的,此時(shí)的上下文不是test1而是test2
test1.z.call(test2)();//10 普通函數(shù)的this是動(dòng)態(tài)作用域的勒叠,此時(shí)為undefined兜挨,被自動(dòng)轉(zhuǎn)化成了全局對(duì)象

箭頭函數(shù)常用于事件綁定、設(shè)置定時(shí)等回調(diào)函數(shù)眯分。例如以下例子中拌汇,原意時(shí)希望1秒后再檢查t的值,但因?yàn)槠胀ê瘮?shù)中的this是動(dòng)態(tài)改變的颗搂,并不能得到想要的結(jié)果担猛。

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

    var t = new test();
    setTimeout(t.y, 1000); //undefined

    t.x = 2;

此時(shí)可以使用箭頭函數(shù)解決,由于箭頭函數(shù)的this不會(huì)隨調(diào)用環(huán)境動(dòng)態(tài)改變丢氢,所以可以得到想要的結(jié)果

    function test(){
        this.x = 1;
        this.y = ()=>{
            console.log(this.x);
        }
    }

    var t = new test();
    setTimeout(t.y, 1000);//2

    t.x = 2;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末傅联,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子疚察,更是在濱河造成了極大的恐慌蒸走,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件貌嫡,死亡現(xiàn)場(chǎng)離奇詭異比驻,居然都是意外死亡该溯,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門别惦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)狈茉,“玉大人,你說(shuō)我怎么就攤上這事掸掸÷惹欤” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵扰付,是天一觀的道長(zhǎng)堤撵。 經(jīng)常有香客問(wèn)我,道長(zhǎng)羽莺,這世上最難降的妖魔是什么实昨? 我笑而不...
    開(kāi)封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮盐固,結(jié)果婚禮上荒给,老公的妹妹穿的比我還像新娘。我一直安慰自己闰挡,他們只是感情好锐墙,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著长酗,像睡著了一般溪北。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上夺脾,一...
    開(kāi)封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天之拨,我揣著相機(jī)與錄音,去河邊找鬼咧叭。 笑死蚀乔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的菲茬。 我是一名探鬼主播吉挣,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼婉弹!你這毒婦竟也來(lái)了睬魂?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤镀赌,失蹤者是張志新(化名)和其女友劉穎氯哮,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體商佛,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡喉钢,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年姆打,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片肠虽。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡幔戏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出税课,到底是詐尸還是另有隱情评抚,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布伯复,位于F島的核電站,受9級(jí)特大地震影響邢笙,放射性物質(zhì)發(fā)生泄漏啸如。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一氮惯、第九天 我趴在偏房一處隱蔽的房頂上張望叮雳。 院中可真熱鬧,春花似錦妇汗、人聲如沸帘不。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)寞焙。三九已至,卻和暖如春互婿,著一層夾襖步出監(jiān)牢的瞬間捣郊,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工慈参, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留呛牲,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓驮配,卻偏偏與公主長(zhǎng)得像娘扩,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子壮锻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

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