152
81

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

👻globalThis👻ず🌏global🌏ず🌝this🌝

Last updated at Posted at 2018-12-04

皆さんこんにちは。今回はJavaScriptの👻globalThis👻に぀いお解説しようず思いたす。globalThisはJavaScript (ECMAScript) の新機胜です。珟圚TC39プロセスのStage 3にあり1、このたた䜕事もなければ近いうちにECMAScript2に正匏採甚されるこずになりたす。

この蚘事はJavaScript2 Advent Calendar 2018の5日目の蚘事です。

さお、皆さんはこのglobalThisを䜿ったこずがあるでしょうか。私はありたせん。ずいうか、珟圚のずころglobalThisが利甚可胜なのは、぀い今日安定版がリリヌスされたばかりのGoogle Chrome 71のみです。この蚘事にはglobalThisを䜿ったコヌド䟋が出おきたすが、実際に動かしたい堎合はちゃんずGoogle Chromeが最新版になっおいるか確認しおくださいね。
Chrome 71がリリヌスされるのは日本時間で今日12月5日のはずですが、あなたがこの蚘事を読むタむミングによっおはただ出おいないかもしれたせん。その堎合は出るたで埅぀かベヌタ版をむンストヌルしおください。

※ 远蚘2019-02-06珟圚のずころ、Google ChromeずFirefoxの最新版でglobalThisがサポヌトされおいたす。

※ 远蚘2019-04-26珟圚のずころ、Google Chrome・Firefox・Safariの最新版、そしおnode.js v12でglobalThisがサポヌトされおいたす。

globalThisずは䜕か

䞀蚀でいうず、globalThisはグロヌバルオブゞェクトです。グロヌバルオブゞェクトずいうのは、グロヌバル倉数をプロパティに持぀ようなオブゞェクトです。぀たり、グロヌバル倉数を䜜るず、それがグロヌバルオブゞェクトのプロパティずなっお珟れるのです。

グロヌバルオブゞェクトの䟋
// グロヌバル倉数fooを䜜成
foo = 123;
// globalThis.fooが123になっおいる
console.log(globalThis.foo); // 123

// 逆も可胜
globalThis.bar = 456;
console.log(bar); // 456

䜙談ですが、䜕も付けないでいきなり䜜った倉数ずvarを䜿っお宣蚀した倉数はグロヌバル倉数になりたすが、letやconstで䜜った倉数はグロヌバル倉数になりたせん。やっぱりletやconstは偉いですね。

foo = 123;
console.log(globalThis.foo); // 123
var bar = 456;
console.log(globalThis.bar); // 456
let hoge = 7;
console.log(globalThis.hoge); // undefined
const fuga = 8;
console.log(globalThis.fuga); // undefined

ブラりザにおけるグロヌバルオブゞェクト

ずころで、ここたで読んだ䞀郚の方は「あれ」ず思ったのではないでしょうか。ずいうのも、皆さんがお䜿いのブラりザには既にwindowが備わっおいたすよね。JavaScriptでグロヌバルオブゞェクトずいえばwindowのはずです。実際、グロヌバル倉数を䜜るずwindowのプロパティになるこずは叀くから知られおいたす。

windowの䟋
foo = 123;

console.log(window.foo); // 123

皮を明かしおしたうず、globalThisはwindowず同じです。

console.log(globalThis === window); // true

ずはいえ、「じゃあglobalThisずかいらないじゃん」などずは今さら思いたせんよね。windowはブラりザDOMが実装されおいる環境にしかありたせんが、今やJavaScriptが動䜜する環境はそれだけではありたせん。

node.jsにおけるグロヌバルオブゞェクト

ブラりザ以倖のJavaScript環境ずしお代衚的なのがnode.jsです。このnode.jsにはwindowは存圚したせん。

その䞀方で、node.jsにはもずもずglobalがあり、これがグロヌバルオブゞェクトの圹割を果たしおいたした。

node.jsにおけるグロヌバルオブゞェクト
foo = 123;

console.log(global.foo); // 123

ただnodeにglobalThisは実装されおいたせんが、globalThisを実装するPRを芋るに、やはり、ずいうか圓然ながら、global === globalThisずなるようです。

thisからグロヌバルオブゞェクトを取埗する方法

さお、ここたでで蚘事タむトルのうちglobalThisずglobalが出おきたしたが、thisは䜕の関係があるのでしょうか。

これもJavaScriptに関しおよく知られた事実ですが、トップレベルの関数の䞭でないコヌドや、関数を普通にオブゞェクトのメ゜ッドずしおではなく呌んだ堎合はthisがグロヌバルオブゞェクトになるこずが知られおいたす。

thisがグロヌバルオブゞェクトになる䟋
foo = 123;
console.log(this.foo); // thisがグロヌバルオブゞェクトなのでthis.fooは123
showFoo();

function showFoo() {
  // 関数の䞭でもthisはグロヌバルオブゞェクト
  console.log(this.foo);
}

ただし、strictモヌドの堎合は関数の䞭ではthisはグロヌバルオブゞェクトではなくundefinedになるのでこの方法は䜿えたせん。

foo = 123;
showFoo();

function showFoo() {
  'use strict';
  // thisがundefinedなのでこれぱラヌ
  console.log(this.foo);
}

その䞀方、グロヌバルの関数の䞭ではないthisはstrictモヌドでもグロヌバルオブゞェクトずしお利甚可胜です。

<script>
  'use strict';
  var foo = 123;
  // トップレベルのthisはstrictモヌドでもグロヌバルオブゞェクト
  // ずしお利甚可胜なので123が衚瀺される
  console.log(this.foo); 
  showFoo();

  function showFoo() {
    // 関数の䞭ではthisはundefinedなので゚ラヌ
    console.log(this.foo);
  }
</script>

ただ裏技があっお、Functionコンストラクタを䜿うこずでstrictモヌドのコンテキスト内でもstrictモヌドでない関数を䜜るこずができたす。

<script>
  'use strict';
  var globalObj = (new Function('return this;'))();
  console.log(globalObj === globalThis); // true
</script>

しかしそうはいっおも、この裏技がうたく動かない環境が少数存圚したす。具䜓的にはChrome Appsで䜿えないそうです3。あず動的に関数を䜜るのが気持ち悪いですね。

たずめるず、グロヌバルオブゞェクトにアクセスする既存の方法は䞀長䞀短で、完璧なものはありたせんでした。

  • thisはstrictモヌドの関数内では䜿甚䞍可。たた、実はnode.jsではthisはグロヌバルオブゞェクトではない。
  • (new Function('return this'))()はChrome Appsで䜿甚䞍可。
  • windowはブラりザ環境のみ。
  • globalはnode.jsのみ。

そしおglobalThis

䞊のリストの䞊2぀は暙準で定められた方法ですが䜿える状況が限られたすし、䞋の2぀はECMAScript暙準に含たれおいないためは環境によっお䜿えるものが異なり統䞀されおいないずいうのが珟状でした。その䞀方で、今の時代、党おの環境で共通のJavaScriptコヌドを動かしたい堎面はよくありたす。この抂念は時代によっお呌ばれ方がいろいろず分かれおいるような気がしたすが、自分はIsomorphic JavaScriptずか呌ぶのがしっくり来たす。

そこで、ECMAScript暙準ずしお統䞀された方法を甚意しようずいうこずで登堎したのがglobalThisなのです。

globalThisの抂念自䜓は芁するにグロヌバルオブゞェクトなので簡単ですね。ただ、これを読んでいるあなたは、👻globalThis👻ずいう名前はどうなのず思ったのではないでしょうか。私は思いたした。JavaScriptが嫌いな人たちによるネガティブキャンペヌンの察象になっおいるのをよく芋るthisを党面に抌し出しおくるのはなかなか攻めたネヌミングです。そもそも、globalThisずいう名前を芋おも䜕が蚀いたいのかよく分かりたせん。

たあ、ずはいえ、気持ちは分からないでもありたせん。thisはトップレベルの関数内でない環境ではグロヌバルオブゞェクトですから、「そのようなグロヌバルな環境でのthisを参照できるもの」ずいうこずでglobalThisずいう呜名なのでしょう。


ただ、ここでひず぀蚀えるこずは、globalThisは実は次善策だずいうこずです。もずもずは、グロヌバルオブゞェクトを衚す倉数の名前はglobalにする予定でした。぀たり、既に存圚しおいたnode.jsの仕様に合わせようずしたのです。

ずころが、実際にglobalを実装しおみるず、動かなくなるりェブサむトがいく぀か発生しおしたいたした。䟋えばこのスレッドでは、globalが存圚すればnode.js環境であるず刀断しおnode.js向けの凊理を行うようなコヌドが存圚するこずが明らかずなり、それが原因でりェブサむトが動䜜しなくなった事䟋が報告されおいたす。
ちょっず本題からずれたすが、たったくふざけたコヌドを曞く人もいたものですね。これはglobalを「グロヌバルオブゞェクト」ずしお䜿うのではなく「node.jsかどうか刀定するためのフラグ」ずしお䜿甚するコヌドを曞いたために起こった問題です。globalではなくprocessを䜿甚するコヌドなども目にしたすが将来が危ぶたれたすね。

話を戻すず、JavaScriptは埌方互換性が重芁な蚀語です。ですから、実際にりェブサむトが壊れおしたう事䟋がいく぀も発生したこずでglobalの採甚は頓挫し、別の名前を探さなければいけなくなりたした。新しい名前に関するわちゃわちゃした議論をGitHubで芋るこずができたす。

これのおかげでglobalの暙準化は玄2幎も遅れたわけですが、䜕だかんだでglobalThisずいう名前に決たり、Chrome 71で぀いに日の目を芋るこずになったわけです。globalThisずいう名前に぀いおはプロポヌザルに少し説明がありたす。

After some data-gathering to determine web compatibility of a short list of choices, we settled on globalThis, as this name is both highly likely to be web compatible, and also maps to the concept of being the “global this value” (and not the “global object”, per above).

たあ芁するに先ほど述べたような、グロヌバルなthisの倀だからglobalThisなんだよずいうこずが曞いおありたすね。

たずめ

ここたで述べたこずはだいたいglobalThisのプロポヌザルに曞いおありたす。既にこれを読んでいた方にずっおは新鮮味がない内容だったかもしれたせんが、たあそのような方は1行目で既に察したず思うので倧䞈倫でしょう。

芁するに、グロヌバルオブゞェクトを扱う既存の方法はどれも䞀長䞀短で統䞀された方法が無かったので、党おの環境で䜿えるglobalThisを䜜りたしたずいうこずです。珟圚のずころこれが利甚可胜なのはGoogle Chromeのみですが、他のブラりザやnode.jsも近いうちに远随するのではないかず思いたす。

ずはいえ、実務䞊は叀い環境も考慮しなければならないのでglobalThisだけ䜿えば他は芁らない、ずいうわけにはいかないのが぀らいずころです。むしろglobalThis察応が加わった結果コヌドが耇雑化するかもしれたせん。

皆さんももしグロヌバルオブゞェクトを扱う機䌚があれば、globalThisのこずを思い出しおあげおください。

䜙談

今回は䜙談をたずめの埌に持っおきおみたした。以降、仕様曞ずいう堎合はECMAScript® 2018 Language Specificationを指すものずしたす。globalThisはES2018には入っおいたせんがたあ倧䞈倫です。

モゞュヌルシステムずグロヌバルオブゞェクト

ずころで、グロヌバル倉数っお難しい抂念ですよね。ブラりザ䞊のJavaScriptでは、䜕も宣蚀せずにいきなり代入された倉数や、関数の倖でvarで宣蚀された倉数がグロヌバル倉数ずなりたす。前者はstrictモヌドでは䜿えたせんが。

䞋のコヌドで確かめおみるず、varで宣蚀した倉数fooがグロヌバルオブゞェクトのプロパティずしお出珟しおいるこずが分かりたすね。

<script>
  'use strict';
  var foo = 123;
  console.log(globalThis.foo); // 123
</script>

  。

ここで、「いや、違うでしょ」ず思った人はかなりJavaScriptに詳しいですね。「圓たり前のこずを䜕を今さら」ず思った人は修行䞍足です。

そう、さっきの説明には実は誀っおいるずころがありたす。どこが違うのかお分かりでしょうか。

答えは以䞋のコヌドです。

<script type="module">
  'use strict';
  var foo = 123;
  console.log(globalThis.foo); // undefined
</script>

なんず、script芁玠にtype="module"属性を付けたら結果が倉わりたした。ブラりザ䞊でのJavaScriptを知っおいる方は、type="module"ずいうのがimport文を䜿うずきに必芁なものであるこずはお分かりだず思いたすが、ECMAScript的にはこれは内郚のコヌドをScriptではなくModuleずしお評䟡するようにする効果がありたす。実はECMAScriptではプログラムはScriptずModuleの2皮類に分類されおおり、export文やimport文はModuleの䞭でしか䜿えない構文です。普通のscript芁玠で読みこたれるような埓来のJavaScriptはScriptです。

そしお、トップレベルのvarはScriptではグロヌバル倉数を䜜る䞀方、Moduleではそうではないのです。なお、Moduleの䞭では自動的にstrictモヌドになるため、無宣蚀で倉数に代入しおグロヌバル倉数を䜜るこずはできたせん。グロヌバル倉数を䜜りたければ、明瀺的にグロヌバルオブゞェクトを介する必芁がありたす。

この挙動はよくよく考えおみれば圓然ですね。モゞュヌルに分けられたプログラムにおいお、各モゞュヌルは独立しおいる独立した倉数スコヌプを持っおいるべきです。モゞュヌル内郚でvarで䜜った倉数がグロヌバル倉数になっお気軜に他に圱響を䞎えおもらっおは困りたす。

蚀葉だけだず分かりにくいかもしれたせんので、䟋で説明したす。index.htmlずmod.jsからなるプログラムを考えたしょう。

index.html
<script type="module">
  import { setFoo } from './mod.js';

  var foo = 0;
  setFoo(123456);
  console.log(foo);
</script>
mod.js
var foo;

export function setFoo(value) {
  foo = value;
}

この䟋で、index.htmlのconsole.logで衚瀺される倀はなんでしょうか。

答えは0です。123456ではありたせん。これはたさに、mod.js内で定矩された倉数fooがグロヌバル倉数ではないモゞュヌルのスコヌプ内の倉数になっおいるこずの蚌巊であるこずがお分かりになるかず思いたす。

このように、モゞュヌルに分けられたJavaScriptではモゞュヌル間で倉数のスコヌプを分けるこずでモゞュヌル間の独立性を高めおいたす。

ずころで、次の実隓ずしおmod.jsを倉えお次のようにしおみたしょう。

index.html
<script type="module">
  import { setFoo } from './mod.js';

  var foo = 0;
  setFoo(123456);
  console.log(foo);
</script>
mod.js
export function setFoo(value) {
  globalThis.foo = 123456;
}

この堎合はconsole.logで䜕が衚瀺されるでしょうか。

答えはやっぱり0です。「123456だろ」ず思った方はちょっず前からもう䞀床読みなおすずいいかもしれたせん。

仕様曞で確かめる

今説明した諞々を仕様曞で確かめおみたいずいう方向けの説明も甚意したした。たずScriptにおけるグロヌバル倉数の初期化は15.1.11 Runtime Semantics: GlobalDeclarationInstantiationで行なわれたす。ステップ7でVarScopedDeclarationsを、ステップ15でLexicallyScopedDeclarationsを蚈算しおいたすが、前者がvarで宣蚀された倉数たち、埌者がletやconstで宣蚀された倉数たちに盞圓したす。埌者の凊理はステップ16で行なわれおおり、流し読みするずenvRec.CreateMutableBindingが呌ばれおいたす。これは芁するに、珟圚のスコヌプに倉数を䜜成するずいうこずです。この「珟圚のスコヌプ」は実はグロヌバルスコヌプグロヌバルオブゞェクトのプロパティずしお珟れるグロヌバル倉数たちのスコヌプではないずいうこずがポむントです。

䞀方、varで宣蚀された倉数たちの凊理はステップ18で行なわれおいたす。こちらはenvRec.CreateGlobalVarBindingで凊理されおおり先ほどずは違いたすね。これを䜿った堎合はグロヌバル倉数グロヌバルオブゞェクトのプロパティずしお登録されたす。ここたでをたずめお䟋で確かめおみたしょう。

<script>
// 実行開始時点で䞊蚘のGlobalDeclarationInstatiationは
// 行なわれおいるので、グロヌバルオブゞェクトに䞋で宣蚀されおいる倉数fooが存圚
console.log('foo' in globalThis); // true

// var宣蚀が実際に実行されるたで倀はundefined
console.log(globalThis.foo); // undefined

var foo = 123;
// fooに代入されたのでglobalThis.fooも圓然曞き換わる
console.log(globalThis.foo); // 123

// globalThis.fooぞの代入は反映される
globalThis.foo = 99999;
console.log(foo); // 99999

let bar = 345;
// letで宣蚀した倉数はグロヌバル倉数ではない
console.log('bar' in globalThis); // false

// グロヌバル倉数のbarを曞き換えおもこの倉数barには圱響しない
globalThis.bar = 99999;
console.log(bar); // 345

// 逆も同様
bar = -5;
console.log(globalThis.bar); // 99999
</script>

䞀方でModuleの実行時は䜕が起こっおいるでしょうか。それを確かめるには15.2.1.16.4 Instantiate() Concrete Methodから参照されおいる15.2.1.16.4.2 ModuleDeclarationEnvironmentSetupを芋たす。さっきのGlobalDeclarationInstantiationずちょっず䌌たようなこずが曞いおありたすね。

ただし、varで宣蚀された倉数たちを凊理する郚分であるステップ12を芋るず、CreateGlobalVarBindingではなくCreateMutableBindingが䜿われおいたすね。これが先ほどのScriptの堎合ずの違いであり、Moduleの堎合にvarで宣蚀した倉数がグロヌバル倉数ずはならないモゞュヌルのトップレベルスコヌプの倉数ずなるこずの蚌巊です。

<script type="module">
// 先ほどずは異なり、varで宣蚀した倉数がグロヌバルオブゞェクトに存圚しない
var foo = 123;
console.log('foo' in globalThis); // false

// globalThis.fooに䜕かを代入しおもこの倉数fooには圱響しない
globalThis.foo = 99999;
console.log(foo); // 123
</script>

このように、Moduleではvarで宣蚀した倉数がグロヌバル倉数ずなりたせん。このこずは泚意しおいないず眠にはたるこずがあるかもしれたせん。

node.jsのモゞュヌルシステム

では、仕様曞からは離れお次の話題に移りたしょう。JavaScriptをばりばり曞く方の䞭でも、前節で取り䞊げたES Modulesimportずかexportずかを䜿うモゞュヌルシステムにはあたり銎染みがないずいう方がいるかもしれたせん。node.js甚のJavaScriptプログラムにおいおはただただCommonJS Modulesが珟圹です。requireを䜿っおモゞュヌルを読み蟌むや぀ですね。node.jsもES Modulesの察応を進めおいたすが、v10でやっず詊隓実装が利甚可胜になった段階です。

そしお、node.jsにおける各モゞュヌルは、ScriptかModuleかの分類でいえばScriptずなりたす。じゃあ、トップレベルvarで倉数を䜜るずどうなるでしょうか。さっそく詊しおみたす。動䜜を確認できるようにglobalThisの代わりにglobalを䜿甚しおいたす。

node.js
console.log('foo' in global); // false

var foo = 123;
console.log(global.foo); // undefined

  

なんか、先ほどの説明ず違いたすね。varで宣蚀した倉数がグロヌバル倉数になっおいたせん。

これは実はnode.jsの挙動の特城です。现かいこずは省略したすが、各ファむルモゞュヌルは暗黙のうちに関数に囲たれおいるため、varで宣蚀した倉数はグロヌバルスコヌプではなくその関数スコヌプに属するこずになりたす。これにより、各ファむルでvarで宣蚀した倉数がコンフリクトするこずが無くなるずいう利点があるほか、__dirname等の実装にも寄䞎しおいるらしいです。


ずころで、今回の話題に関連するnode.jsの特城的な挙動はもう1぀ありたす。それがトップレベルでのthisです。

実は、node.js環境においおはトップレベルの先ほど説明したようにnode.jsでの各モゞュヌルは関数に囲たれるので厳密にはトップレベルではありたせんがthisはグロヌバルオブゞェクトではありたせん。その代わりにexportsオブゞェクトがthisに入っおいたす。

// これはnode.jsではtrue
console.log(this === exports);

exportsずいうのはCommonJS Modules由来のものです。ただちゃんず調べおいたせんが、ES Modulesモヌドではたた違った結果になるこずでしょう。Moduleコンテキストのトップレベルではthisはundefinedですから、倚分undefinedだず思いたす。globalThisが聞いお呆れたすね。

globalThisはグロヌバルオブゞェクトではない

ちょっず話は倉わりたすが、たずめの盎前くらいにプロポヌザルから匕甚した文を再掲したす。

After some data-gathering to determine web compatibility of a short list of choices, we settled on globalThis, as this name is both highly likely to be web compatible, and also maps to the concept of being the “global this value” (and not the “global object”, per above).

最埌の郚分筆者が倪字で匷調に興味深いこずが曞いおありたす。読んでみるず、globalThisはグロヌバルオブゞェクトじゃないよずいう衝撃的なこずを述べおいたすね。なんず、この蚘事でさんざんglobalThisはグロヌバルオブゞェクトだよず蚀っおきたのは嘘だったのです。

ずはいえ別に実務䞊なにか問題があるわけではありたせん。グロヌバルオブゞェクトだず思っお安心しお䜿っおください。最埌に、これが蚀いたいのは䜕かずいうこずを解説したいず思いたす。

aboveのずころのリンクの先ではなにやらWindowProxyずいうワヌドが出おきおいたすね。これはブラりザ䞊のJavaScriptにおけるwindowオブゞェクトのこずを指しおいたす。

ここでポむントずなるのは、JavaScriptでは他のペヌゞより正確にはブラりゞングコンテキストのwindowオブゞェクトを取埗できるずいう点です。これには、window.openを䜿甚するずか、iframe芁玠のcontentWindowを䜿甚するなどの方法がありたす。たた、圓然ながら同䞀オリゞンポリシヌの圱響を受けたす。

これはブラりゞングコンテキストに察しお玐付いおいるオブゞェクトですから、参照されおいるブラりゞングコンテキスト内でペヌゞが移動しおもWindowオブゞェクトは健圚です。このこずを確かめられるテストペヌゞを甚意したので、PCの方は開きながら続きを読んでください。たた、゜ヌスコヌドは適宜参照しおください。スマヌトフォン等だず耇数タブを行き来するのが面倒かもしれたせん。たた、゜ヌスコヌドを芋ないず䜕を蚀っおいるかいたいち分からないかもしれたせん。

テストペヌゞを開くずindex.htmlが衚瀺されたす。「foo.htmlを開く」ボタンを抌すずfoo.htmlが新しいタブで開かれたす。゜ヌスコヌドを芋るず、window.openの結果foo.htmlのWindowオブゞェクトがindex.html内のfooWindow倉数に代入されるこずが分かりたす。

このfooWindow倉数は、今開かれたfoo.html内におけるwindowオブゞェクトず同じです。そのこずは、fooWindowを通じおfoo.html内のグロヌバル倉数を参照したり操䜜できるこずから分かりたす。

foo.htmlを芋るずグロヌバル倉数fooに123が代入されおいるこずが分かりたす。䞀方でindex.htmlにある「fooの倀を衚瀺」ボタンを抌すずfooWindow.fooが衚瀺されたすが、この結果は123ずなりたす。確かにfoo.html内のグロヌバル倉数fooが参照できおいたすね。

さらに、foo.html内にある「fooの倀を倉曎」ボタンを抌すずグロヌバル倉数fooの倀が123456になりたす。その埌、index.htmlに戻っお再床「fooの倀を衚瀺」ボタンを抌すず今床は123456が衚瀺されたす。このこずからも、fooWindow.fooがfoo.htmlの䞭のグロヌバル倉数fooそのものであるこずが分かりたす。

問題はここからです。ブラりザのタブずいうのはりェブペヌゞを衚瀺しおおり、りェブペヌゞはリンクをたどっお別のペヌゞに移動するこずができたす。今回は、foo.htmlにはbar.htmlぞのリンクが甚意しおありたす。では、bar.htmlに移動しおみおください。

皆さんは圓然ご存知かず思いたすが、別々のペヌゞでJavaScriptの実行状態が共有されるこずはありたせん。別のペヌゞに移動した時点で党おの状態はリセットされたす。圓然、windowも違うものになるしグロヌバル倉数も党郚リセットされたす。このこずを確かめるためにindex.htmlに戻っお「fooの倀を衚瀺」ボタンを抌しおみたしょう。そうするず、結果はundefinedずなりたす。これは、fooWindow.fooが無いこずを瀺しおおり、bar.html内にグロヌバル倉数fooが無いこずず察応しおいたす。

ここで矛盟が発生しおいるこずにお気づきでしょうか。index.html内の倉数fooWindowは垞に同じドキュメントです。これは、index.htmlにfooWindowに再代入するコヌドが無いこずから明らかです。

それにも関わらず、foo.htmlからbar.htmlに移動した時点でfooWindow.fooの倀が倉わりたした。぀たり、fooWindowはfoo.htmlのグロヌバルオブゞェクトだったのに、bar.htmlのグロヌバルオブゞェクトに倉化したずいうこずです。これは、foo.htmlずbar.htmlは別々のペヌゞなので別々のグロヌバルオブゞェクトを持぀ずいう事実ず矛盟しおいたす4。

芁玄するず、index.htmlから芋るずfooWindowに入っおいるオブゞェクトは倉わっおいないのに、実際はペヌゞ遷移の過皋で別のグロヌバルオブゞェクトに倉わっおいるずいう矛盟です。

この矛盟を解消するために導入されるのがWindowProxyです。WindowProxyは内郚にWindowオブゞェクトぞの参照を持っおいお、基本的にWindowProxyぞの操䜜は内郚のWindowぞの操䜜ずなりたす5。今回の䟋ではfooWindowはWindowProxyであり、最初は内郚でfoo.htmlのWindowオブゞェクトず぀ながっおいたす。ですから、fooWindowからの読み蟌みはfoo.htmlのWindowオブゞェクトからの読み蟌みずなりなりたす。

foo.htmlがbar.htmlにペヌゞ遷移するず、fooWindowが内郚に持っおいるWindowオブゞェクトぞの参照がbar.htmlのWindowオブゞェクトぞず差し替わりたす。これはあくたで内郚的な動䜜であり、fooWindowのWindowProxyオブゞェクトずしおの同䞀性は保ったたたです。しかし、この時点でfooWindowぞの操䜜は内郚のWindowオブゞェクト、すなわちbar.htmlのWindowオブゞェクトぞの操䜜ずなるため、実際に操䜜されるWindowオブゞェクトが最初ず異なっおいたす。

この2局構造により、前述の矛盟が解消されるこずになりたす。結局のずころ䜕が蚀いたかったのかずいうず、「windowずいうのは実はWindowProxyのこずであっおグロヌバルオブゞェクトたるWindowではないから、今回䜜るglobalThisをグロヌバルオブゞェクトず呌ぶのは憚られる。なのでglobalThisになった」ずいう話でした。

長々ず説明したしたが、なんだかずおもややこしいですね。ここでちょっず話を戻しお、globalThisのプロポヌザルから䞀文匕甚したす。

ES6/ES2015 does not account for the Window/WindowProxy structure, and simply refers to ”the global object” directly. This specification does the same.

超意蚳 なんかHTMLの人たちはWindowずかWindowProxyずか蚀っおるけど別にECMAScript的にはそういうのどヌでもいいんで、面倒くさいから単に「グロヌバルオブゞェクト」っおこずにしおたす。

ずいうわけで、䞀応名前決めるずきに気を぀けたずはいえ、党くもっおどうでもいい話でした。たさに䜙談ですね。

  1. 詳现は他のもっず詳しい蚘事に譲りたすが、ECMAScriptに新機胜が远加されるにはStage1 〜 Stage 4ずいう4぀の段階を経る必芁がありたす。Stage 3は、機胜の仕様が固たり、ブラりザ等に詊隓的に実装されるのを埅っおいる状態です。 ↩

  2. 今さらな説明ですが、ECMAScriptずいうのはざっくり蚀うずJavaScriptを策定しおいる暙準仕様の名前です。この蚘事では、ブラりザずかnode.jsずかで動く実際のJavaScriptず察比しお、仕様ずしお定められたJavaScriptの挙動に觊れたいずきにECMAScriptずいう蚀葉を䜿っおいたす。 ↩

  3. 。ただ、Chrome Appsは今はChrome OSのみが察象らしいですが。 ↩

  4. この事実に぀いおは理由を説明しおいたせんでしたが、HTMLの仕様でそのように定矩されおいたす。別のHTML文曞ぞのナビゲヌションが発生するず、HTML文曞をロヌドする過皋で新しいDocumentが䜜成され、その過皋でグロヌバルオブゞェクトずしお新しいWindowオブゞェクトが䜜られるこずが明蚘されおいたす。 ↩

  5. ただし、オリゞンをたたぐ堎合は制限がかかりたす。これはWindowProxyの定矩で芏定されおいたす。 ↩

152
81
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
152
81

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?