第七章 this關(guān)鍵字

  • 涵義
  • 使用場(chǎng)合
  • 使用注意點(diǎn)
  • 綁定this的方法

涵義

??this對(duì)象是在運(yùn)行時(shí)基于函數(shù)的執(zhí)行環(huán)境綁定的:在全局函數(shù)中键菱,this等于window吧秕,而當(dāng)函數(shù)被作為某個(gè)對(duì)象的方法調(diào)用時(shí)不铆,this等于那個(gè)對(duì)象。不過(guò)匿名函數(shù)的執(zhí)行環(huán)境具有全局性,因此其this對(duì)象通常指向window傻昙,這個(gè)地方可以這么理解廊谓,如果一個(gè)在函數(shù)體內(nèi)的變量沒(méi)有定義就表示是全局變量梳猪,那么函數(shù)沒(méi)有命名也可以理解為全局函數(shù),所以執(zhí)行環(huán)境也是全局蒸痹,可以暫時(shí)這么理解春弥。
??簡(jiǎn)單來(lái)說(shuō)this就是函數(shù)運(yùn)行時(shí)所在的對(duì)象(環(huán)境)。this是會(huì)根據(jù)運(yùn)行環(huán)境的不同而發(fā)生改變但是作用域鏈不會(huì)隨著運(yùn)行環(huán)境的改變而改變叠荠,只跟聲明時(shí)所在的作用域有關(guān)匿沛。例:

var a = {
   name: 'nike',
   decript: function () {
       return this.name
   }
}
var b = {
    name: 'addidas'
}
b.decript = a.decript
b.decript()    //  addidas

通過(guò)上面例子我們可以看到decript方法所在的對(duì)象(運(yùn)行環(huán)境)發(fā)生了改變,this的指向也就發(fā)生改變榛鼎。下面的例子可以讓我們理解的更透徹:

var a = {
   name: '張三',
   descript: function () {
       return this.name
   }
}
var name = '李四'
var f = a.descript
f()     // 李四

上述例子中a.descript是一個(gè)方法賦值給變量f逃呼,變量f的運(yùn)行環(huán)境是全局,所以this.name就是李四者娱,我們最終要看的是this所在函數(shù)的運(yùn)行環(huán)境(對(duì)象)抡笼。

使用場(chǎng)合

(1)全局環(huán)境
全局環(huán)境使用this,它指的就是頂層對(duì)象window黄鳍。
(2)構(gòu)造函數(shù)
構(gòu)造函數(shù)中的this推姻,指的是實(shí)例對(duì)象。例:

var Obj =function (p) {
    this.p = p
}
var o = new Obj('hollo world')
// o.p = hollo world

上面定義了一個(gè)構(gòu)造函數(shù)Obj框沟,然后new這個(gè)構(gòu)造函數(shù)賦值給o藏古,因?yàn)閚ew是調(diào)用的意思,所以就是調(diào)用構(gòu)造函數(shù)賦值給o忍燥,運(yùn)行環(huán)境也是在o中所以this指向的也是o拧晕。
(3)對(duì)象的方法

var obj ={
  foo: function () {
    console.log(this);
  }
};
obj.foo()    //    obj

使用注意點(diǎn)

(1)避免多層this
由于this的指向是不確定的,所以切勿在函數(shù)中包含多層this灾前。

var name = 'nike'
var o = function () {
    var name = 'addidas'
    f1: function () {
      console.log(this.name)
      var f2 = function () {
        console.log(this.name)
      }()
  }
}
o.f1() 
addidas
nike

第一個(gè)this指向o防症,第二個(gè)因?yàn)槭悄涿瘮?shù)所以指向的是window
javascript嚴(yán)格模式下,如果this指向window就會(huì)報(bào)錯(cuò)。
(2)避免數(shù)組處理方法中的this
數(shù)組中的map和forEach方法蔫敲,允許提供一個(gè)函數(shù)作為參數(shù)饲嗽,這個(gè)函數(shù)內(nèi)部不應(yīng)該使用this。

var o = {
   v: 'hello',
   p: ['a1', 'a2'],
   f: function f() {
      this.p.forEach(function (item) => {
        console.log(this.v + ' ' + item)
    })
  }
}
o.f()
undefined a1
undefined a2

第一個(gè)this指向的是o奈嘿,第二個(gè)this指向的是window貌虾,因?yàn)槭悄涿瘮?shù),如果想要只要外層函數(shù)而不是頂層函數(shù)裙犹,可以用下面的方法:

var o = {
   v: 'hello',
   p: ['a1', 'a2'],
   f: function f() {
     var that = this
      this.p.forEach(function (item) => {
        console.log(that .v + ' ' + item)
    })
  }
}
o.f()
hello    a1
hello   a2

將this的值固定指向o就可以了尽狠,還有一種方法就是將this當(dāng)做forEach的第二個(gè)參數(shù),固定this的運(yùn)行環(huán)境

var o = {
   v: 'hello',
   p: ['a1', 'a2'],
   f: function f() {
      this.p.forEach(function (item) => {
        console.log(this.v + ' ' + item)
    }, this)
  }
}
o.f()
hello    a1
hello   a2

上述兩種方法都是固定this的運(yùn)行環(huán)境
(3)避免回調(diào)函數(shù)中的this
回調(diào)函數(shù)中的this往往會(huì)改變指向叶圃,最好避免使用

var o = new Object()
o.f = function () {
    console.log(this === o) 
}
$('button').on('click', o.f)

上面代碼中點(diǎn)擊按鈕顯示false袄膏,原因是此時(shí)this不再指向o,而是指向按鈕的dom對(duì)象掺冠,因?yàn)閒方法是在按鈕對(duì)象的環(huán)境中調(diào)用的沉馆。為了解決這個(gè)問(wèn)題可以采用下面一些方法對(duì)this進(jìn)行綁定,也就使得this固定指向某個(gè)對(duì)象德崭,減少不確定性斥黑。

綁定this的方法

javascript提供了call、apply眉厨、bind這三個(gè)方法固定/切換this的指向锌奴。
(1)call()
函數(shù)實(shí)例的call方法,可以指定函數(shù)內(nèi)部this的指向(即函數(shù)執(zhí)行時(shí)所在的對(duì)象)憾股,然后在指定的對(duì)象中調(diào)用該函數(shù)鹿蜀。

var obj = {}
var f = function () {
   return this
}
f() === window       // true
f.call(obj) === obj   // true

上面代碼中call方法中的參數(shù)應(yīng)該是一個(gè)對(duì)象,如果參數(shù)為空荔燎、null和undefined耻姥,則默認(rèn)傳入全局對(duì)象。

var n = 123;
var obj = { n: 456 };
function a() {
  console.log(this.n);
}
a.call() // 123
a.call(null) // 123
a.call(undefined) // 123
a.call(window) // 123
a.call(obj) // 456

call方法還可以接受多個(gè)參數(shù)

func.call(thisValue, arg1, arg2, ...)

call的第一個(gè)參數(shù)就是this所要指向的那個(gè)對(duì)象有咨,后面的參數(shù)則是函數(shù)調(diào)用時(shí)所需的參數(shù)琐簇。

function add(a, b) {
  return a + b;
}
add.call(this, 1, 2) // 3

(2)apply()
apply方法的作用與call方法類似,也是改變this指向座享,然后再調(diào)用該函數(shù)婉商。唯一的區(qū)別就是,它接收一個(gè)數(shù)組作為函數(shù)執(zhí)行時(shí)的參數(shù)渣叛,使用格式如下丈秩。

func.apply(thisValue, [arg1, arg2, ...])

利用apply方法的特點(diǎn)可以做一些有趣的東西,比如用這個(gè)方法找出數(shù)組中最大的元素淳衙。

var a = [0, 3, 5, 7, 9]
Math.max.apply(null, a)   // 9

轉(zhuǎn)換類似數(shù)組的對(duì)象

利用數(shù)組對(duì)象的slice方法蘑秽,可以將一個(gè)類似數(shù)組的對(duì)象(比如arguments對(duì)象)轉(zhuǎn)為真正的數(shù)組饺著。

Array.prototype.slice.apply({0: 1, length: 1}) // [1]
Array.prototype.slice.apply({0: 1}) // []
Array.prototype.slice.apply({0: 1, length: 2}) // [1, undefined]
Array.prototype.slice.apply({length: 1}) // [undefined]

上面代碼的apply方法的參數(shù)都是對(duì)象,但是返回結(jié)果都是數(shù)組肠牲,這就起到了將對(duì)象轉(zhuǎn)成數(shù)組的目的幼衰。從上面代碼可以看到,這個(gè)方法起作用的前提是缀雳,被處理的對(duì)象必須有l(wèi)ength屬性渡嚣,以及相對(duì)應(yīng)的數(shù)字鍵。

綁定回調(diào)函數(shù)的對(duì)象

前面的按鈕點(diǎn)擊事件的例子肥印,可以改寫如下识椰。

var o = new Object();
o.f = function () {
  console.log(this === o);
}
var f = function (){
  o.f.apply(o);
  // 或者 o.f.call(o);
};
// jQuery 的寫法
$('#button').on('click', f);

點(diǎn)擊按鈕返回的是true,由于apply方法(或者call方法)不僅綁定函數(shù)執(zhí)行時(shí)所在的對(duì)象深碱,還會(huì)立即執(zhí)行函數(shù)腹鹉,因此不得不把綁定語(yǔ)句寫在一個(gè)函數(shù)體內(nèi)。更簡(jiǎn)潔的寫法是采用下面介紹的bind方法莹痢。
(3)bind()
bind方法用于將函數(shù)體內(nèi)的this綁定到某個(gè)對(duì)象种蘸,然后返回一個(gè)新函數(shù)。

var counter = {
  count: 0,
  inc: function () {
    this.count++;
  }
};
var func = counter.inc.bind(counter);
func();
counter.count // 1

我們可以看到用bind方法返回的是一個(gè)方法竞膳,并不會(huì)執(zhí)行,這一點(diǎn)跟apply和call是不同的诫硕,后者會(huì)改變this指向并且立即執(zhí)行但是bind只會(huì)改變this指向并不會(huì)執(zhí)行坦辟。這三種方法是類似的。

利用bind改變forEach章办、map方法中的this指向

var obj = {
  name: '張三',
  times: [1, 2, 3],
  obj.print = function () {
  this.times.forEach(function (n) {
    console.log(this.name);
  }.bind(this));
};
};
obj.print()
// 張三
// 張三
// 張三

改變遍歷方法中的this指向就用這種方式锉走,也可以把bind(this)直接改為this或者call(this)、apply(this)

結(jié)合call方法使用

利用bind方法藕届,可以改寫一些 JavaScript 原生方法的使用形式挪蹭,以數(shù)組的slice方法為例。

[1, 2, 3].slice(0, 1) // [1]
// 等同于
Array.prototype.slice.call([1, 2, 3], 0, 1) // [1]
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末休偶,一起剝皮案震驚了整個(gè)濱河市梁厉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌踏兜,老刑警劉巖词顾,帶你破解...
    沈念sama閱讀 212,029評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異碱妆,居然都是意外死亡肉盹,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門疹尾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)上忍,“玉大人骤肛,你說(shuō)我怎么就攤上這事∏侠叮” “怎么了萌衬?”我有些...
    開封第一講書人閱讀 157,570評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)它抱。 經(jīng)常有香客問(wèn)我秕豫,道長(zhǎng),這世上最難降的妖魔是什么观蓄? 我笑而不...
    開封第一講書人閱讀 56,535評(píng)論 1 284
  • 正文 為了忘掉前任混移,我火速辦了婚禮,結(jié)果婚禮上侮穿,老公的妹妹穿的比我還像新娘歌径。我一直安慰自己,他們只是感情好亲茅,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評(píng)論 6 386
  • 文/花漫 我一把揭開白布回铛。 她就那樣靜靜地躺著,像睡著了一般克锣。 火紅的嫁衣襯著肌膚如雪茵肃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,850評(píng)論 1 290
  • 那天袭祟,我揣著相機(jī)與錄音验残,去河邊找鬼。 笑死巾乳,一個(gè)胖子當(dāng)著我的面吹牛您没,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播胆绊,決...
    沈念sama閱讀 39,006評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼氨鹏,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了压状?” 一聲冷哼從身側(cè)響起仆抵,我...
    開封第一講書人閱讀 37,747評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎何缓,沒(méi)想到半個(gè)月后肢础,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,207評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡碌廓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評(píng)論 2 327
  • 正文 我和宋清朗相戀三年传轰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谷婆。...
    茶點(diǎn)故事閱讀 38,683評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡慨蛙,死狀恐怖辽聊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情期贫,我是刑警寧澤跟匆,帶...
    沈念sama閱讀 34,342評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站通砍,受9級(jí)特大地震影響玛臂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜封孙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評(píng)論 3 315
  • 文/蒙蒙 一迹冤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧虎忌,春花似錦泡徙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至挑围,卻和暖如春礁竞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贪惹。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工苏章, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人奏瞬。 一個(gè)月前我還...
    沈念sama閱讀 46,401評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像泉孩,于是被迫代替她去往敵國(guó)和親硼端。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評(píng)論 2 349

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

  • 第2章 基本語(yǔ)法 2.1 概述 基本句法和變量 語(yǔ)句 JavaScript程序的執(zhí)行單位為行(line)寓搬,也就是一...
    悟名先生閱讀 4,132評(píng)論 0 13
  • 涵義 this關(guān)鍵字是一個(gè)非常重要的語(yǔ)法點(diǎn)珍昨。毫不夸張地說(shuō),不理解它的含義句喷,大部分開發(fā)任務(wù)都無(wú)法完成镣典。 首先,thi...
    許先生__閱讀 551評(píng)論 0 4
  • 第5章 引用類型(返回首頁(yè)) 本章內(nèi)容 使用對(duì)象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,219評(píng)論 0 4
  • 函數(shù)和對(duì)象 1唾琼、函數(shù) 1.1 函數(shù)概述 函數(shù)對(duì)于任何一門語(yǔ)言來(lái)說(shuō)都是核心的概念兄春。通過(guò)函數(shù)可以封裝任意多條語(yǔ)句,而且...
    道無(wú)虛閱讀 4,550評(píng)論 0 5
  • 老家舊屋子的一個(gè)角落上锡溯,放著一口當(dāng)年可以裝七八擔(dān)水的大水缸赶舆。水缸里盛著不滿一缸的紅薯淀粉哑姚,我們那里通俗的叫淀粉為紅...
    林智宏閱讀 707評(píng)論 0 2