JS 中的 this

由于綁定期的特性价说,JS中的 this 含義很多辆亏,它可以是全局對(duì)象、當(dāng)前對(duì)象或者任意對(duì)象鳖目,這完全取決于函數(shù)的調(diào)用方式

隨著函數(shù)使用場合的不同扮叨,this的值會(huì)發(fā)生變化
總的原則:this指的是 調(diào)用函數(shù)的那個(gè)對(duì)象

作為函數(shù)調(diào)用 (以下有三種情況)


在全局下和函數(shù)被直接調(diào)用時(shí) this 綁定到全局對(duì)象(瀏覽器中的全局對(duì)象 window
被直接調(diào)用 fn1 可以理解為:window.fn1()

console.log(this);

function fn1(){
    console.log(this);
}

fn1();

內(nèi)部函數(shù)

函數(shù)嵌套產(chǎn)生的內(nèi)部函數(shù)的 this 不是其父函數(shù),仍然是全局變量(記憶)

function fn0(){
    function fn(){
        console.log(this);
    }
    fn();
}

fn0();

setTimeout领迈、setInterval

上面兩個(gè)方法的執(zhí)行函數(shù) this 也是全局對(duì)象

document.addEventListener('click', function(e){
    console.log(this); // this 指的是 事件源DOM對(duì)象
    setTimeout(function(){
        console.log(this); // this 指的是 全局對(duì)象
    }, 200);
}, false);

作為構(gòu)造函數(shù)調(diào)用


所謂構(gòu)造函數(shù)彻磁,就是通過這個(gè)函數(shù)生成一個(gè)新對(duì)象(object)。這是惦费,this 指的是這個(gè)新對(duì)象

重溫 new 運(yùn)算符:
new 運(yùn)算符接受一個(gè)函數(shù) F 及其參數(shù): new F(arguments)兵迅。這一過程分為三步:

  1. 創(chuàng)建類的實(shí)例。這步是把一個(gè)空的對(duì)象的 __proto__ 屬性設(shè)置為 F.prototype
  2. 初始化實(shí)例薪贫。函數(shù) F 被傳入?yún)?shù)并調(diào)用,關(guān)鍵字 this 被設(shè)定為該實(shí)例刻恭。
  3. 返回實(shí)例瞧省。
function Person(name){
    this.name = name;
}
Person.prototype.printName = function(){
    console.log(this.name);
};
// 
var p1 = new Person('Byron');
var p2 = new Person('Casper');
var p3 = new Person('Vincent');
// 
p1.printName(); // 每個(gè) this 為調(diào)用其方法的實(shí)例
p2.printName();
p3.printName();

作為對(duì)象方法調(diào)用


在 JavaScript 中,函數(shù)也是對(duì)象鳍贾,因此函數(shù)可以作為一個(gè)對(duì)象的屬性鞍匾,此時(shí)該函數(shù)被稱為該對(duì)象的方法,在使用這種調(diào)用方式時(shí)骑科,this 被自然綁定到該對(duì)象

var obj1 = {
    name: 'Byron',
    fn : function(){
        console.log(this);
    }
};

obj1.fn(); // obj1

注意下面這種情況:函數(shù)名 實(shí)際上就是一個(gè)地址橡淑,可以通過賦值給 fn2,調(diào)用時(shí)不會(huì)再去管obj1咆爽,fn2 執(zhí)行時(shí)可以理解為 window.fn2 調(diào)用

var fn2 = obj1.fn

fn2() // window

DOM對(duì)象綁定事件

在事件處理程序中 this 代表事件源DOM對(duì)象(低版本IE有bug梁棠,指向了window)

document.addEventListener('click', function(e){
    console.log(this); // 事件源DOM對(duì)象
    var _document = this;
    setTimeout(function(){
        console.log(this); // window 全局對(duì)象
        console.log(_document); // 事件源DOM對(duì)象
    }, 200);
}, false);

Function.prototype.bind

bind置森,返回一個(gè)新函數(shù),并且使函數(shù)內(nèi)部的 this 為傳入的第一個(gè)參數(shù)
下面的代碼改寫上面需要注意的賦值情況

var fn3 = obj1.fn.bind(obj1) 

fn3() // obj1 

使用 call 和 apply 設(shè)置 this

call apply符糊,調(diào)用一個(gè)函數(shù)凫海,傳入函數(shù)執(zhí)行上下文及其參數(shù)

fn.call(context, param1, param2...)

fn.apply(context, paramArray)

語法同樣簡單,第一個(gè)參數(shù)都是希望設(shè)置的 this 對(duì)象男娄,不同之處在于 call 方法接收參數(shù)列表行贪,而 apply 接收參數(shù)數(shù)組

call 舉例

function sum() { // 用 call 實(shí)現(xiàn)參數(shù)的累加
    var result = 0
    Array.prototype.forEach.call(arguments, function(value) {
        result += value
    })
    return result
}
// 另一種方法
function sum2() {
    var result = 0
    // 下面將 參數(shù)列表 轉(zhuǎn)變成數(shù)組
    var argsArr = Array.prototype.slice.call(arguments, 0)
    console.log(Array.isArray(argsArr)) // true
    argsArr.forEach(function(value) {
        result += value
    })
    return result
}

apply 舉例

var arr = [3,1,0,2,-10,99,20]
// Math.max( 3,1,0,2,-10,99,20 )
console.log(Math.max.apply(null, arr)) //  99
console.log(Math.min.apply(null, arr)) // -10

caller

在函數(shù) A 調(diào)用函數(shù) B 時(shí),被調(diào)用函數(shù) B 會(huì)自動(dòng)生成一個(gè) caller 屬性模闲,指向調(diào)用它的函數(shù)對(duì)象建瘫,如果函數(shù)當(dāng)前未被調(diào)用,或并非被其他函數(shù)調(diào)用尸折,則 callernull

arguments

  1. 在函數(shù)調(diào)用時(shí)啰脚,會(huì)自動(dòng)在該函數(shù)內(nèi)部生成一個(gè)名為 arguments 的隱藏對(duì)象
  2. 該對(duì)象類似于數(shù)組,可以使用 [ ] 運(yùn)算符獲取函數(shù)調(diào)用時(shí)傳遞的實(shí)參
  3. 只有函數(shù)被調(diào)用時(shí)翁授,arguments 對(duì)象才會(huì)創(chuàng)建拣播,未調(diào)用時(shí)其值為 null

callee (嚴(yán)格模式不可用)

當(dāng)函數(shù)被調(diào)用時(shí),它的 arguments.callee 對(duì)象就會(huì)指向自身收擦,也就是一個(gè)對(duì)自己的引用

由于 arguments 在函數(shù)被調(diào)用時(shí)才有效贮配,因此 arguments.callee 在函數(shù)未調(diào)用時(shí)是不存在的(即 null.callee ),且引用它會(huì)產(chǎn)生異常

function fn6(){
    console.log(arguments.callee);
}
fn6();

匿名函數(shù)特好用

var i =0;
window.onclick = function(){
    console.log(i);
    if(i<5){
        i++;
        setTimeout(arguments.callee, 200);
    }
} // 0 1 2 3 4 5

函數(shù)的執(zhí)行環(huán)境


JavaScript中的函數(shù)既可以被當(dāng)作普通函數(shù)執(zhí)行塞赂,也可以作為對(duì)象的方法執(zhí)行泪勒,這是導(dǎo)致 this 含義如此豐富的主要原因

一個(gè)函數(shù)被執(zhí)行時(shí),會(huì)創(chuàng)建一個(gè)執(zhí)行環(huán)境(ExecutionContext)宴猾,函數(shù)的所有的行為均發(fā)生在此執(zhí)行環(huán)境中圆存,構(gòu)建該執(zhí)行環(huán)境時(shí),JavaScript 首先會(huì)創(chuàng)建 arguments變量仇哆,其中包含調(diào)用函數(shù)時(shí)傳入的參數(shù)

接下來創(chuàng)建作用域鏈沦辙,然后初始化變量。首先初始化函數(shù)的形參表讹剔,值為 arguments變量中對(duì)應(yīng)的值油讯,如果 arguments變量中沒有對(duì)應(yīng)值,則該形參初始化為 undefined延欠。

如果該函數(shù)中含有內(nèi)部函數(shù)陌兑,則初始化這些內(nèi)部函數(shù)。如果沒有由捎,繼續(xù)初始化該函數(shù)內(nèi)定義的局部變量兔综,需要注意的是此時(shí)這些變量初始化為 undefined,其賦值操作在執(zhí)行環(huán)境(ExecutionContext)創(chuàng)建成功后,函數(shù)執(zhí)行時(shí)才會(huì)執(zhí)行软驰,這點(diǎn)對(duì)于我們理解JavaScript中的變量作用域非常重要涧窒,最后為this變量賦值,會(huì)根據(jù)函數(shù)調(diào)用方式的不同碌宴,賦給this全局對(duì)象杀狡,當(dāng)前對(duì)象等

至此函數(shù)的執(zhí)行環(huán)境(ExecutionContext)創(chuàng)建成功,函數(shù)開始逐行執(zhí)行贰镣,所需變量均從之前構(gòu)建好的執(zhí)行環(huán)境(ExecutionContext)中讀取

三種變量


  • 實(shí)例變量:(this)類的實(shí)例才能訪問到的變量
  • 靜態(tài)變量:(屬性)直接類型對(duì)象能訪問到的變量
  • 私有變量:(局部變量)當(dāng)前作用域內(nèi)有效的變量
function ClassA(){
    var a = 1; //私有變量呜象,只有函數(shù)內(nèi)部可以訪問
    this.b = 2; //實(shí)例變量,只有實(shí)例可以訪問
}

ClassA.c = 3; // 靜態(tài)變量碑隆,也就是屬性恭陡,類型訪問

console.log(a); // error
console.log(ClassA.b) // undefined
console.log(ClassA.c) //3 

var classa = new ClassA();
console.log(classa.a);//undefined
console.log(classa.b);// 2
console.log(classa.c);//undefined c 只是在 ClassA函數(shù)上

薦讀:
this 的值到底是什么?一次說清楚
你怎么還沒搞懂 this上煤?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末休玩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子劫狠,更是在濱河造成了極大的恐慌拴疤,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件独泞,死亡現(xiàn)場離奇詭異呐矾,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)懦砂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門蜒犯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人荞膘,你說我怎么就攤上這事罚随。” “怎么了羽资?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵淘菩,是天一觀的道長。 經(jīng)常有香客問我屠升,道長瞄勾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任弥激,我火速辦了婚禮,結(jié)果婚禮上愿阐,老公的妹妹穿的比我還像新娘微服。我一直安慰自己,他們只是感情好缨历,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布以蕴。 她就那樣靜靜地躺著糙麦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪丛肮。 梳的紋絲不亂的頭發(fā)上赡磅,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音宝与,去河邊找鬼焚廊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛习劫,可吹牛的內(nèi)容都是我干的咆瘟。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼诽里,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼袒餐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起谤狡,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤灸眼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后墓懂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體焰宣,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年拒贱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了宛徊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡逻澳,死狀恐怖闸天,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情斜做,我是刑警寧澤苞氮,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站瓤逼,受9級(jí)特大地震影響笼吟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜霸旗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一贷帮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧诱告,春花似錦撵枢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽潜必。三九已至,卻和暖如春沃但,著一層夾襖步出監(jiān)牢的瞬間磁滚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國打工宵晚, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留垂攘,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓坝疼,卻偏偏與公主長得像搜贤,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子钝凶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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

  • 函數(shù)和對(duì)象 1仪芒、函數(shù) 1.1 函數(shù)概述 函數(shù)對(duì)于任何一門語言來說都是核心的概念。通過函數(shù)可以封裝任意多條語句耕陷,而且...
    道無虛閱讀 4,527評(píng)論 0 5
  • 沒搞錯(cuò)吧掂名!js寫了那么多年,this還是會(huì)搞錯(cuò)哟沫!沒搞錯(cuò)饺蔑,javascript就是回搞錯(cuò)! ………… 在寫java的...
    zhoulujun閱讀 1,436評(píng)論 0 11
  • 前言 近期對(duì)this很感興趣嗜诀,于是乎簡單整理了一些關(guān)于this的技術(shù)點(diǎn)猾警,加深一下對(duì)this的理解。 非箭頭函數(shù) 在...
    little_short閱讀 405評(píng)論 0 0
  • 最近在看《你不知道的JavaScript(上卷)》隆敢,覺得書中關(guān)于this的知識(shí)點(diǎn)講解的比較透徹易懂发皿,在此做一些整理...
    jeff_nz閱讀 588評(píng)論 0 0
  • “這個(gè)妹妹我曾見過”寶玉初見黛玉時(shí)說,上輩子的情緣拂蝎,今世的愛戀穴墅,有些情總是似曾相識(shí)。 二姐說温自,對(duì)農(nóng)業(yè)的情懷玄货,其實(shí)每...
    沙沙細(xì)雨閱讀 649評(píng)論 0 2