質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

3回答

928閲覧

javascriptのwindowsオブジェクトについて

gomengo

総合スコア51

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2017/09/22 22:51

編集2017/09/23 05:22

mouseflowというサービスを利用して、javascriptでサイトのトラッキングをしようとしています。

javasriptを使用してsubmitを行っているページはうまくトラッキング出来ない為、下記のページを参考にして、ソースの修正を行いました。

https://mouseflow-jp.com/forms-with-no-successful-submits/

しかし、うまくトラッキングを行うことができません。
上記サービスの英語のページは、下記となります。

http://help.mouseflow.com/knowledge_base/topics/troubleshooting-forms-with-no-successful-submits

日本語のサイトであると、_mfq のオブジェクトを作成は、下記のようになっています。

javascript

1var _mfq = _mfq || [];

英語のサイトを見ると、下記のようになります。

javascript

1window._mfq = window._mfq || [];

windowsオブジェクトは、省略できるということなのですが、上記の挙動というのは全く同じということになるのでしょうか?

よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

変数宣言文

JavaScript

1window._mfq = window._mfq || [];

こちらのコードは、このコードが実行されるタイミングで window._mfq のtruthy判定し、値を代入します。

JavaScript

1var _mfq = _mfq || [];

こちらのコードも、このコードが実行されるタイミングで _mfq のtruthy判定して値を代入しますが、var による変数の実体化処理が別途走ります。
var の初期化処理は特殊で前方に遡って、undefined で初期化するのです。
var が記述された場所がグローバルコードならグローバルコードの先頭で変数を undefined で初期化し、関数コードなら関数の先頭で変数をundefined で初期化します。

詳しい使い方は下記スレッドの私の回答を読んでみて下さい。

window キーワード

window キーワードでグローバルオブジェクトを参照できる機能は、HTML Standard によって規定されています。

しかし、全てのJavaScript実装が HTML Standard を実装しているわけではない為、JavaScript 実装によっては window キーワードによってグローバルオブジェクトを参照できません。
そこで、ECMAScript という基本仕様に則り、キーワードを使わずにグローバルオブジェクトを参照する事で、実装依存性を無くすことが出来ます。

HTML

1<script> 2/** 3 * このコードは ES6 の module ではないグローバルコードです 4 */ 5 6'use strict'; // Strict Mode を指定します 7 8/** 9 * (1) グローバルコード 10 */ 11var global = this; // グローバルコードにおける this はグローバルオブジェクトを参照します 12 13/** 14 * (2) 関数コード1 15 */ 16(function () { 17 var global = this; // Function#call で束縛された為、グローバルコードと同じようにグローバルオブジェクトを参照出来ます 18}.call(this)); // グローバルコードからグローバルオブジェクトを引き渡します 19 20/** 21 * (3) 関数コード2 22 */ 23(function () { 24 var global = Function('return this')(); // Function() 内の関数コードはグローバルスコープで実行されます 25}()); 26</script>

Strict Mode

JavaScript には「Strict Mode」と「非Strict Mode」の二種類の実行形式が存在します。
Strict Mode を指定するには、コード中に "use strict"; を記述します。

JavaScript

1<script> // module ではない 2'use strict'; 3console.log(this); // Window (グローバルコードでは、this 値はグローバルオブジェクトを参照する) 4 5(function () { 6 console.log(this); // undefined (関数コードでは undefined を参照する) 7}()); 8</script>

非Strict Modeを指定するには、"use strict"; を記述しません。

JavaScript

1<script> // module ではない 2'use strict'; 3console.log(this); // Window (グローバルコードでは、this 値はグローバルオブジェクトを参照する) 4 5(function () { 6 console.log(this); // Window (関数コードでもグローバルオブジェクトを参照する) 7}()); 8</script>

なお、JavaScript では this 値は関数が実行されたタイミングで決定されるものであり、関数の呼び出し方によっては例外があります。

  • Function#call, Function#apply, Function#bind
  • アロー関数
  • addEventListener の第二引数
  • Array#forEach の第二引数

module (ECMAScript 6 規定)

ES6 の module を使った場合には、事情が大きく異なります。
module を使う事は質問されているコードを推奨せず、module を使ったコードを推奨する回答となります。
これは前述の私のスタンスと矛盾する為、本スレッドの別の記事で新しく回答しました。

更新履歴

  • 2017/09/23 23:50 「Strict Mode」「module (ECMAScript 6 規定)」節を追加。「window キーワード」節の文面変更。

Re: gomengo さん

投稿2017/09/22 23:53

編集2017/09/23 15:14
think49

総合スコア18156

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gomengo

2017/09/23 05:41

関数内で、 var _mfq = _mfq || []; と定義した場合、_mfqはグローバルの変数ということになるのでしょうか?
raccy

2017/09/23 06:25

実装依存しないグローバルオブジェクトのコードですが、moduleモードでは(1)と(2)が動きません。(最新のChromeまたはSafariで試してください。EdgeおよびFirefoxではフラグを有効にしないとmoduleモードは動作しません。) (1) https://jsbin.com/mixitobezu/edit?html,console (2) https://jsbin.com/yetifisono/edit?html,console 下はmoduleモードでも正常に動作します。 (3) https://jsbin.com/docebayuzu/edit?html,console window決め打ち https://jsbin.com/butemofaha/edit?html,console core-jsのpolyfill https://jsbin.com/cecokofaba/edit?html,console しかし、(3)についてはContent-Security-Policyが設定されている環境ではUncaught EvalError(Chromeの場合)が発生し、同じく動作しません。 全ての環境で動作することを想定するのであれば、中途半端に自分で書くよりも、core-js等のPolyfillを勧めた方がいいのでは無いでしょうか?
think49

2017/09/23 15:09

To: gomengo さん 関数コードにおいての this は Strict Mode では undefined、非Strict Mode ではグローバルオブジェクトが規定値です。 ただし、addEventListenerの第二引数におけるイベントハンドラ関数等、this 値は呼び出し側で自由に束縛できるものですので、呼び出し方によっては例外があります。 親記事に追記しておきました。 To: raccy さん 私が意図した「全ての実装で動作することを想定」とは全ての実装で HTML Standard 仕様を実装しているわけではない、という事です。 window キーワードによってグローバルオブジェクトを参照できるのはブラウザが「7.3 The Window object」を実装しているからです。 しかし、その仕様を実装していない環境も当然あります。 これを解決する為には、「ECMAScript の範疇で」グローバルオブジェクトを参照する必要があります。 そうすれば、ECMAScript を実装している全ての環境で同じように動くことが期待できます。 moduleモードやContent-Security-Policyにおける影響の問題は実装による問題とは思いません。 ブラウザは <script></script> 内のグローバルコードにおいて、this でグローバルオブジェクトを参照できますが、<script type="module"> はそうではありません。 ならば、これは「ユーザがどの方法を選択するか」という設計上の問題といえます(Content-Security-Policyに至ってはECMAScript範囲外の問題なので、レイヤーも違います)。 「window キーワードによってグローバルオブジェクトを参照できるか」という問題は書き方で解決できるものではないので、実装の問題と私は考えました。 問題の性質は大きく異なっていると思います。 > 全ての環境で動作することを想定するのであれば、中途半端に自分で書くよりも、core-js等のPolyfillを勧めた方がいいのでは無いでしょうか? はい。moduleに言及する事は、そういう事になりますね。 ただ、この回答は私の当初の意図とは異なっていて、 https://teratail.com/questions/87024 で言及した状況に近いと思っています。 そういう意見もある事は理解していますが、この回答の中で触れる事ではないと考えています。
raccy

2017/09/23 15:44

私が危惧していたのは、編集前の回答では「どんな場合でも使える方法」という風に読めてしまったことです。この場合は使えません、この場合だけ使えますという注意事項があれば問題ないと思います。
guest

0

module (ECMAScript 6 規定)

JavaScript

1var _mfq = _mfq || [];

この書き方はグローバル変数が衝突したなら、そのまま使い、衝突しなければ配列を生成して返すコードです。
しかし、「そもそも衝突させるべきではない」という考え方も出来ます。

ECMAScript 6 では各種ライブラリの依存関係を解決する為に module が定義されました。
ブラウザにおいては、HTML Standard で定義された <script type="module"> と組み合わせる事で機能します。

JavaScript

1/** 2 * test.js 3 */ 4export const foo = 1; // 変数 foo をエクスポート 5export const bar = 'bar'; // 変数 bar をエクスポート

HTML

1<script type="module" src="test.js"></script> 2<script type="module"> 3import {foo} from './test.js'; // test.js の変数 foo をインポート 4console.log(foo); // 1 5console.log(this); // undefined (module 内の this 値は undefined) 6console.log(bar); // ReferenceError: bar is not defined (test.js 内の変数 bar はインポートしていない為、参照できない) 7</script>

名前を変えてインポート

別々のmoduleから同じ名前の変数をそのままの状態でインポートすることは出来ません。

HTML

1<script type="module"> 2import {foo} from './test1.js'; 3import {foo} from './test2.js'; // SyntaxError: Identifier 'foo' has already been declared 4</script>

別々のmoduleから同じ名前の変数をインポートするには、名前を変えてインポートします。

HTML

1<script type="module"> 2import {foo as foo1} from './test1.js'; 3import {foo as foo2} from './test2.js'; 4console.log(foo1); 5console.log(foo2); 6</script>

モジュール間のグローバルオブジェクトは共有される

モジュール間のグローバルオブジェクトは共有される為、グローバルオブジェクトを介して、データを共有する事が可能です。
が、module を使っているにも関わらず、グローバル変数で衝突させているという点で module のメリットを相殺する好ましくない書き方です。

JavaScript

1/** 2 * test1.js 3 */ 4var global = Function('return this')(), 5 fuga = 'fuga!';; 6 7global.fuga = 'fuga' in global ? global.fuga + fuga : fuga;

JavaScript

1/** 2 * test2.js 3 */ 4var global = Function('return this')(), 5 fuga = 'fuga!fuga!'; 6 7global.fuga = 'fuga' in global ? global.fuga + fuga : fuga;

HTML

1<script type="module" src="test1.js"></script> 2<script type="module" src="test2.js"></script> 3<script type="module"> 4console.log(fuga); // fuga!fuga!fuga! 5</script>

所感

raccyさんのmodule管理における問題点の指摘を受け、書きましたが、前の私の回答とはベクトルの違う回答であった為、新しく回答しました。
私としては、まだこの書き方は実装が整っていないという点で時期早々だと思いますが、最新の機能に触れておくのも悪くはないですね。

Re: gomengo さん

投稿2017/09/23 14:31

編集2017/09/23 14:37
think49

総合スコア18156

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

グローバル変数としての定義としては同じですね。

function内に記述するのであれば、windowをつけた方が安全かと思います。
下記は参考まで

JavaScriptのグローバル変数はwindowオブジェクトのプロパティ

投稿2017/09/23 01:55

n884

総合スコア100

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問