函數(shù)調(diào)用模式的區(qū)別-this

前言

學(xué)習(xí)js也快有一段時(shí)間了,一直不怎么想碰this,也碰到別人寫(xiě)的一些關(guān)于this,一直懶得看,但是最近在學(xué)習(xí)DOM事件,寫(xiě)代碼中經(jīng)城@玻看見(jiàn)this,有時(shí)候理解的不太透徹,所以決定把它研究一下,當(dāng)然了,現(xiàn)在寫(xiě)的this也只是我現(xiàn)在的水平和參考一下大神的文章,自己結(jié)合起來(lái),寫(xiě)給自己的

正文:

引自 MDN this

  • 與其他語(yǔ)言相比品洛,函數(shù)的 this關(guān)鍵字在JavaScript中的表現(xiàn)略有不同,此外,在嚴(yán)格模式非嚴(yán)格模式之間也會(huì)有一些差別。
  • 在絕大多數(shù)情況下,函數(shù)的調(diào)用方式?jīng)Q定了this的值瘫怜。this不能在執(zhí)行期間被賦值,并且在每次函數(shù)被調(diào)用時(shí)this的值也可能會(huì)不同本刽。ES5引入了bind方法來(lái)設(shè)置函數(shù)的this值鲸湃,而不用考慮函數(shù)如何被調(diào)用的,ES2015引入了支持this詞法解析的箭頭函數(shù)(它在閉合的執(zhí)行上下文內(nèi)設(shè)置this
    的值)子寓。

什么是this?

this是在執(zhí)行上下文創(chuàng)建時(shí)確定的一個(gè)在執(zhí)行過(guò)程中不可更改的變量暗挑。

  • 所謂執(zhí)行上下文,就是JavaScript引擎在執(zhí)行一段代碼之前將代碼內(nèi)部會(huì)用到的一些變量斜友、函數(shù)炸裆、this提前聲明然后保存在變量對(duì)象中的過(guò)程。這個(gè)’代碼片段’包括:全局代碼(script標(biāo)簽內(nèi)部的代碼)鲜屏、函數(shù)內(nèi)部代碼烹看、eval內(nèi)部代碼。而我們所熟知的作用域鏈也會(huì)在保存在這里洛史,以一個(gè)類(lèi)數(shù)組的形式存儲(chǔ)在對(duì)應(yīng)函數(shù)的[[Scopes]]屬性中惯殊。

正文說(shuō):嚴(yán)格模式與飛非嚴(yán)格模式會(huì)有區(qū)別,我們來(lái)看一下:

看一下嚴(yán)格模式下

var a = 1;
function fun() {
   'use strict';
    var a = 2;
    return this.a;
}
fun();  //報(bào)錯(cuò): Cannot read property 'a' of undefined

非嚴(yán)格模式下:

var a = 1;
function fun() {
    var a = 2;
    return this.a;
}
fun();  // 輸出 1

總結(jié): 當(dāng)函數(shù)獨(dú)立調(diào)用的時(shí)候,在嚴(yán)格模式下它的this指向undefined也殖,在非嚴(yán)格模式下土思,當(dāng)this指向undefined的時(shí)候,自動(dòng)指向全局對(duì)象(瀏覽器中就是window)


正文說(shuō):絕大多數(shù)情況下,函數(shù)的調(diào)用方式?jīng)Q定了this的值

我們來(lái)看看函數(shù)有幾種調(diào)用方式

  • 函數(shù)調(diào)用模式: 函數(shù)名()
  • 方法調(diào)用模式
  • 構(gòu)造函數(shù)調(diào)用模式 new Function(...)
  • apply(call)調(diào)用模式

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

//例子:
function add(i,j){
  console.log(this);  //Window
  // console.log(arguments);
  var sum = i+j;
  console.log(sum);
  (function(){
    console.log(this);  //Window
  })()
  return sum;
}
add(1,2);

從上面的例子我們看到this兩次返回的都是window全局對(duì)象,匿名函數(shù)也會(huì)產(chǎn)生本地作用域,打印也是window按理說(shuō)第一次打印應(yīng)該是undefined,但是瀏覽器里有一條規(guī)則:

如果你傳的 context 就 null 或者 undefined己儒,那么 window 對(duì)象就是默認(rèn)的 context(嚴(yán)格模式下默認(rèn) context 是 undefined)

總結(jié):函數(shù)調(diào)用模式this指向window的全局對(duì)象

方法調(diào)用模式

//例子:
var myNumber = {
  value: 1,
  add: function(i){
    console.log(this);  //Object{value: 1, add: ?}
    this.value += i;
  }
}
myNumber.add(1);

函數(shù)實(shí)現(xiàn)改變value的值加1,add被調(diào)用時(shí),this的指向是Object對(duì)象

總結(jié):方法調(diào)用模式this指向調(diào)用者

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

//例子:
function Car(type,color){
  this.type = type;
  this.color = color;
  this.status = "stop";
  this.light = "off";
  console.log(this);  //打印結(jié)果是我們創(chuàng)建的對(duì)象
}
Car.prototype.start = function(){
  this.status = "driving";
  this.light = "on";
  console.log(this.type + " is " + this.status);
}
Car.prototype.stop = function(){
  this.status = "stop";
  this.light = "off";
  console.log(this.type + " is " + this.status);
}
var benz = new Car("benz", "black");  //Car {type: "benz", color: "black", status: "stop", light: "off"}

如果函數(shù)作為構(gòu)造函數(shù)用崎岂,那么其中的this就代表它即將new出來(lái)的對(duì)象。為啥呢址愿?new做了啥呢该镣?new做了下面這些事:

  • 創(chuàng)建一個(gè)臨時(shí)對(duì)象
  • 給臨時(shí)對(duì)象綁定原型
  • 給臨時(shí)對(duì)象對(duì)應(yīng)屬性賦值
  • 將臨時(shí)對(duì)象return

也就是說(shuō)new其實(shí)就是個(gè)語(yǔ)法糖冻璃,this之所以指向臨時(shí)對(duì)象還是沒(méi)逃脫上面說(shuō)的幾種情況响谓。
總結(jié):構(gòu)造函數(shù)調(diào)用模式this指向被構(gòu)造的對(duì)象

apply(call)調(diào)用模式

  • this指向第一個(gè)參數(shù)

對(duì)于這一個(gè),由于自己還沒(méi)學(xué)到,先借鑒MDN上的,后面自己再總結(jié)一下

如果要想把this的值從一個(gè)context傳到另一個(gè),就要用call省艳,或者apply
方法娘纷。

// 一個(gè)對(duì)象可以作為call和apply的第一個(gè)參數(shù),并且this會(huì)被綁定到這個(gè)對(duì)象跋炕。
var obj = {a: 'Custom'};

// 這個(gè)屬性是在global對(duì)象定義的赖晶。
var a = 'Global';

function whatsThis(arg) {
  return this.a;  // this的值取決于函數(shù)的調(diào)用方式
}

whatsThis();          // 直接調(diào)用,      返回'Global'
whatsThis.call(obj);  // 通過(guò)call調(diào)用辐烂,  返回'Custom'
whatsThis.apply(obj); // 通過(guò)apply調(diào)用 遏插,返回'Custom'

當(dāng)一個(gè)函數(shù)的函數(shù)體中使用了this關(guān)鍵字時(shí),通過(guò)call()方法和apply()方法調(diào)用纠修,this的值可以綁定到一個(gè)指定的對(duì)象上胳嘲。call()和apply()的所有函數(shù)都繼承自Function.prototype 。

function add(c, d) {
  return this.a + this.b + c + d;
}

var o = {a: 1, b: 3};

// 第一個(gè)參數(shù)是作為‘this’使用的對(duì)象
// 后續(xù)參數(shù)作為參數(shù)傳遞給函數(shù)調(diào)用
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16

// 第一個(gè)參數(shù)也是作為‘this’使用的對(duì)象
// 第二個(gè)參數(shù)是一個(gè)數(shù)組扣草,數(shù)組里的元素用作函數(shù)調(diào)用中的參數(shù)
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34

使用 call 和 apply 函數(shù)的時(shí)候要注意了牛,如果傳遞的 this 值不是一個(gè)對(duì)象,JavaScript 將會(huì)嘗試使用內(nèi)部 ToObject 操作將其轉(zhuǎn)換為對(duì)象辰妙。因此鹰祸,如果傳遞的值是一個(gè)原始值比如 7 或 'foo' ,那么就會(huì)使用相關(guān)構(gòu)造函數(shù)將它轉(zhuǎn)換為對(duì)象密浑,所以原始值 7 通過(guò)new Number(7)被轉(zhuǎn)換為對(duì)象蛙婴,而字符串'foo'使用 new String('foo') 轉(zhuǎn)化為對(duì)象,例如:

function bar() {
  console.log(Object.prototype.toString.call(this));
}

//原始值 7 被隱式轉(zhuǎn)換為對(duì)象
bar.call(7); // [object Number]

參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末敬锐,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子呆瞻,更是在濱河造成了極大的恐慌台夺,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件痴脾,死亡現(xiàn)場(chǎng)離奇詭異颤介,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)滚朵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)冤灾,“玉大人,你說(shuō)我怎么就攤上這事辕近≡隙郑” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵移宅,是天一觀(guān)的道長(zhǎng)归粉。 經(jīng)常有香客問(wèn)我,道長(zhǎng)漏峰,這世上最難降的妖魔是什么糠悼? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮浅乔,結(jié)果婚禮上倔喂,老公的妹妹穿的比我還像新娘。我一直安慰自己靖苇,他們只是感情好席噩,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著贤壁,像睡著了一般悼枢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上芯砸,一...
    開(kāi)封第一講書(shū)人閱讀 51,573評(píng)論 1 305
  • 那天萧芙,我揣著相機(jī)與錄音,去河邊找鬼假丧。 笑死双揪,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的包帚。 我是一名探鬼主播渔期,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼渴邦!你這毒婦竟也來(lái)了疯趟?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤谋梭,失蹤者是張志新(化名)和其女友劉穎信峻,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體瓮床,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡盹舞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年产镐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片踢步。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡癣亚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出获印,到底是詐尸還是另有隱情述雾,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布兼丰,位于F島的核電站玻孟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏地粪。R本人自食惡果不足惜取募,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一琐谤、第九天 我趴在偏房一處隱蔽的房頂上張望蟆技。 院中可真熱鬧,春花似錦斗忌、人聲如沸质礼。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)眶蕉。三九已至,卻和暖如春唧躲,著一層夾襖步出監(jiān)牢的瞬間造挽,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工弄痹, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留饭入,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓肛真,卻偏偏與公主長(zhǎng)得像谐丢,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蚓让,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

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

  • 第5章 引用類(lèi)型(返回首頁(yè)) 本章內(nèi)容 使用對(duì)象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類(lèi)型 使用基本類(lèi)型...
    大學(xué)一百閱讀 3,234評(píng)論 0 4
  • 函數(shù)參數(shù)的默認(rèn)值 基本用法 在ES6之前乾忱,不能直接為函數(shù)的參數(shù)指定默認(rèn)值,只能采用變通的方法历极。 上面代碼檢查函數(shù)l...
    呼呼哥閱讀 3,384評(píng)論 0 1
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理窄瘟,服務(wù)發(fā)現(xiàn),斷路器趟卸,智...
    卡卡羅2017閱讀 134,657評(píng)論 18 139
  • 與其他語(yǔ)言相比蹄葱,函數(shù)的this關(guān)鍵字在JavaScript中的表現(xiàn)略有不同纲酗,此外,在嚴(yán)格模式和非嚴(yán)格模式之間也會(huì)有...
    codingC閱讀 574評(píng)論 0 0
  • 北冥有魚(yú)吮螺,其名為鯤。鯤之大帕翻,不知其幾千里也鸠补;化而為鳥(niǎo),其名為鵬嘀掸。鵬之背紫岩,不知其幾千里也;怒而飛睬塌,其翼若垂天之云泉蝌。是...
    宅家九小姐閱讀 4,827評(píng)論 0 3