JavaScript來(lái)自一門(mén)健全的語(yǔ)言聂抢,所以你可能覺(jué)得JavaScript中的this和其他面向?qū)ο蟮恼Z(yǔ)言如java的this一樣冯凹,是指存儲(chǔ)在實(shí)例屬性中的值龟劲。事實(shí)并非如此,在JavaScript中予借,最好把this當(dāng)成哈利波特中的博格特的背包傅是,有著深不可測(cè)的魔力。
JavaScript中很多時(shí)候會(huì)用到this蕾羊,下面詳細(xì)介紹每一種情況喧笔。在這里我想首先介紹一下宿主環(huán)境這個(gè)概念。一門(mén)語(yǔ)言在運(yùn)行的時(shí)候龟再,需要一個(gè)環(huán)境书闸,叫做宿主環(huán)境。對(duì)于JavaScript利凑,宿主環(huán)境最常見(jiàn)的是web瀏覽器浆劲,瀏覽器提供了一個(gè)JavaScript運(yùn)行的環(huán)境,這個(gè)環(huán)境里面哀澈,需要提供一些接口牌借,好讓JavaScript引擎能夠和宿主環(huán)境對(duì)接。JavaScript引擎才是真正執(zhí)行JavaScript代碼的地方割按,常見(jiàn)的引擎有V8(目前最快JavaScript引擎膨报、Google生產(chǎn))、JavaScript core适荣。JavaScript引擎主要做了下面幾件事情:
- 一套與宿主環(huán)境相聯(lián)系的規(guī)則;
- JavaScript引擎內(nèi)核(基本語(yǔ)法規(guī)范现柠、邏輯、命令和算法);
- 一組內(nèi)置對(duì)象和API;
- 其他約定弛矛。
但是環(huán)境不是唯一的够吩,也就是JavaScript不僅僅能夠在瀏覽器里面跑,也能在其他提供了宿主環(huán)境的程序里面跑丈氓,最常見(jiàn)的就是nodejs周循。同樣作為一個(gè)宿主環(huán)境强法,nodejs也有自己的JavaScript引擎–V8。根據(jù)官方的定義:
Node.js is a platform built on Chrome’s JavaScript runtime for easily building fast, scalable network applications
global this
- 在瀏覽器里湾笛,在全局范圍內(nèi)拟烫,this等價(jià)于window對(duì)象。
<script type="text/javascript">
console.log(this === window); //true
</script>
- 在瀏覽器里迄本,在全局范圍內(nèi),用var聲明一個(gè)變量和給this或者window添加屬性是等價(jià)的课竣。
<script type="text/javascript">
var foo = "bar";
console.log(this.foo); //logs "bar"
console.log(window.foo); //logs "bar"
</script>
- 如果你在聲明一個(gè)變量的時(shí)候沒(méi)有使用var或者let(ECMAScript 6),你就是在給全局的this添加或者改變屬性值嘉赎。
<script type="text/javascript">
foo = "bar";
function testThis() {
foo = "foo";
}
console.log(this.foo); //logs "bar"
testThis();
console.log(this.foo); //logs "foo"
</script>
- 在node環(huán)境里,如果使用REPL(Read-Eval-Print Loop于樟,簡(jiǎn)稱(chēng)REPL:讀取-求值-輸出,是一個(gè)簡(jiǎn)單的公条,交互式的編程環(huán)境)來(lái)執(zhí)行程序,this并不是最高級(jí)的命名空間,最高級(jí)的是global.
> this
{ ArrayBuffer: [Function: ArrayBuffer],
Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 },
Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 },
...
> global === this
true
- 在node環(huán)境里迂曲,如果執(zhí)行一個(gè)js腳本靶橱,在全局范圍內(nèi),this以一個(gè)空對(duì)象開(kāi)始作為最高級(jí)的命名空間路捧,這個(gè)時(shí)候关霸,它和global不是等價(jià)的。
test.js腳本內(nèi)容:
console.log(this);
console.log(this === global);
REPL運(yùn)行腳本:
$ node test.js
{}
false
- 在node環(huán)境里杰扫,在全局范圍內(nèi)队寇,如果你用REPL執(zhí)行一個(gè)腳本文件,用var聲明一個(gè)變量并不會(huì)和在瀏覽器里面一樣將這個(gè)變量添加給this章姓。
test.js:
var foo = "bar";
console.log(this.foo);
$ node test.js
undefined
- 但是如果你不是用REPL執(zhí)行腳本文件佳遣,而是直接執(zhí)行代碼,結(jié)果和在瀏覽器里面是一樣的(神坑)凡伊。
> var foo = "bar";
> this.foo
bar
> global.foo
bar
- 在node環(huán)境里零渐,用REPL運(yùn)行腳本文件的時(shí)候,如果在聲明變量的時(shí)候沒(méi)有使用var或者let系忙,這個(gè)變量會(huì)自動(dòng)添加到global對(duì)象诵盼,但是不會(huì)自動(dòng)添加給this對(duì)象。如果是直接執(zhí)行代碼银还,則會(huì)同時(shí)添加給global和this
test.js
foo = "bar";
console.log(this.foo);
console.log(global.foo);
$ node test.js
undefined
bar
上面的八種情況可能大家已經(jīng)繞暈了拦耐,總結(jié)起來(lái)就是:在瀏覽器里面this是老大,它等價(jià)于window對(duì)象见剩,如果你聲明一些全局變量(不管在任何地方)杀糯,這些變量都會(huì)作為this的屬性。在node里面苍苞,有兩種執(zhí)行JavaScript代碼的方式固翰,一種是直接執(zhí)行寫(xiě)好的JavaScript文件狼纬,另外一種是直接在里面執(zhí)行一行行代碼。對(duì)于直接運(yùn)行一行行JavaScript代碼的方式骂际,global才是老大疗琉,this和它是等價(jià)的。在這種情況下歉铝,和瀏覽器比較相似盈简,也就是聲明一些全局變量會(huì)自動(dòng)添加給老大global,順帶也會(huì)添加給this太示。但是在node里面直接腳本文件就不一樣了柠贤,你聲明的全局變量不會(huì)自動(dòng)添加到this,但是會(huì)添加到global對(duì)象类缤。所以相同點(diǎn)是臼勉,在全局范圍內(nèi),全局變量終究是屬于老大的餐弱。
function this
無(wú)論是在瀏覽器環(huán)境還是node環(huán)境宴霸, 除了在DOM事件處理程序里或者給出了thisArg(接下來(lái)會(huì)講到)外,如果不是用new調(diào)用膏蚓,在函數(shù)里面使用this都是指代全局范圍的this瓢谢。
<script type="text/javascript">
foo = "bar";
function testThis() {
this.foo = "foo";
}
console.log(this.foo); //logs "bar"
testThis();
console.log(this.foo); //logs "foo"
</script>
test.js
foo = "bar";
function testThis () {
this.foo = "foo";
}
console.log(global.foo);
testThis();
console.log(global.foo);
$ node test.js
bar
foo
- 除非你使用嚴(yán)格模式,這時(shí)候this就會(huì)變成undefined驮瞧。
<script type="text/javascript">
foo = "bar";
function testThis() {
"use strict";
this.foo = "foo";
}
console.log(this.foo); //logs "bar"
testThis(); //Uncaught TypeError: Cannot set property 'foo' of undefined
</script>
我更喜歡把新的值稱(chēng)作一個(gè)實(shí)例恩闻。
函數(shù)里面的this其實(shí)相對(duì)比較好理解,如果我們?cè)谝粋€(gè)函數(shù)里面使用this剧董,需要注意的就是我們調(diào)用函數(shù)的方式幢尚,如果是正常的方式調(diào)用函數(shù),this指代全局的this翅楼,如果我們加一個(gè)new尉剩,這個(gè)函數(shù)就變成了一個(gè)構(gòu)造函數(shù),我們就創(chuàng)建了一個(gè)實(shí)例毅臊,this指代這個(gè)實(shí)例理茎,這個(gè)和其他面向?qū)ο蟮恼Z(yǔ)言很像。另外管嬉,寫(xiě)JavaScript很常做的一件事就是綁定事件處理程序皂林,也就是諸如button.addEventListener(‘click’, fn, false)之類(lèi)的,如果在fn里面需要使用this蚯撩,this指代事件處理程序?qū)?yīng)的對(duì)象础倍,也就是button。
時(shí)間有限胎挎,未完待續(xù)沟启。忆家。。