teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

2

関数宣言と関数式、 グローバルコード上の this 値

2018/05/06 16:31

投稿

think49
think49

スコア18194

answer CHANGED
@@ -78,4 +78,60 @@
78
78
  いずれも私が気を付けていることは、**main 関数がグローバルコードと同じ this 値を持っていること**です。
79
79
  が、これは私の個人的なポリシーであり、標準的な基準があるわけではありません。
80
80
 
81
+ ### 関数宣言と関数式
82
+
83
+ > function(){ ... } はラムダ式の定義、
84
+
85
+ 式の定義という意味では正しいのですが、実は条件があります。
86
+
87
+ | 関数の種類 | 制限事項 |
88
+ | ------------------------------ | ------------------------------------------------------------ |
89
+ | 関数宣言 (FunctionDeclaration) | function キーワードで始まらなければならず、名前をつけなければならない |
90
+ | 関数式 (FunctionExpression) | function キーワードで始まってはならず、名前は付けても付けなくても良い |
91
+
92
+ 関数宣言は**function キーワードで始まらなければならない**と決まっている為、いわゆる即時関数と呼ばれる書き方では `()` や `+` 等を先頭に置くことで関数式化しています。
93
+
94
+ ```JavaScript
95
+ (function main () { // "(" で始める事で関数式扱いとなる (関数式なので名前は付けても良い)
96
+ console.log(main.name);
97
+ }());
98
+ ```
99
+
100
+ ### グローバルコード上の this 値
101
+
102
+ > thisはDOMツリーのルートということなのですね。
103
+
104
+ これは違います。
105
+ DOM 規定ではなく、ECMAScript 規定によって、「**グローバルコード上では this 値がグローバルオブジェクトである**」と定められています。
106
+ そして、`window` キーワードでグローバルオブジェクトを参照できるのは、DOM 規定によるものです。
107
+
108
+ ```JavaScript
109
+ /**
110
+ * グローバルコード
111
+ */
112
+ window.parseFloat('1.0'); // (A)
113
+ this.parseFloat('1.0'); // (B)
114
+ ```
115
+
116
+ 上記コードは、Webブラウザ上ではどちらも期待通りに動作しますが、Node.js では (A) が動作せず、(B) のみ期待通りに動作するでしょう。
117
+ Node.js は window キーワードでグローバルオブジェクトを参照できませんが、ECMAScript 仕様は実装されています。
118
+ その為、ECMAScript 仕様の範囲内である `this` 値による参照は有効なのです。
119
+
120
+ ---
121
+
122
+ ちなみに、DOM 上のルートノードは元々は `document` でした。
123
+ Document Object Model の名が示す通りですね。
124
+ ですので、`document.parentNode` は未定義です。
125
+
126
+ `window` は長らく、標準化されていませんでしたが、HTML Standard の既定と同時に `window` オブジェクトが定義され、DOM Standard でも定義されました。
127
+
128
+ - [HTML Standard — Window object, WindowProxy exotic object(日本語訳)](https://triple-underscore.github.io/HTML-window-ja.html#the-window-object)
129
+ - [4.2. Node tree - DOM Standard](https://dom.spec.whatwg.org/#node-trees)
130
+
131
+ DOM Standard では少し、複雑で3つのツリーが出てきます。
132
+
133
+ - Node tree上 に Document は存在しますが、Window は存在しません
134
+ - Document tree 上の root は document です
135
+ - Shadow tree 上の root は ShadowRoot であり、Window です
136
+
81
137
  Re: Chironian さん

1

main() 関数の代替

2018/05/06 16:31

投稿

think49
think49

スコア18194

answer CHANGED
@@ -1,3 +1,5 @@
1
+ ### JavaScriptの実行タイミング
2
+
1
3
  > これに対してJavaScriptの関数がいつ呼ばれるのか?の把握が甘そうなのです。
2
4
 
3
5
  綺麗にまとまっているサイトが思い浮かばなかったので、下記にまとめました。
@@ -12,4 +14,68 @@
12
14
 
13
15
  不明点や誤りがあれば対応しますので、気軽に聞いてください。
14
16
 
17
+ ### main() 関数の代替
18
+
19
+ JavaScriptの場合、関数を自由に定義できるので main 関数という概念はありませんが、ES3, ES5 時代にはグローバル汚染を回避する為に即時関数で括る慣習がありました。
20
+
21
+ ```JavaScript
22
+ <script>
23
+ /**
24
+ * (A) ES3/ES5
25
+ */
26
+ 'use strict';
27
+ (function () { // FunctionExpression
28
+ function handleClick (event) {
29
+ console.log(event.type);
30
+ }
31
+
32
+ function main () {
33
+ this.document.addEventListener('click', handleClick, false);
34
+ }
35
+
36
+ main.call(this);
37
+ }.call(this));
38
+ </script>
39
+ ```
40
+
41
+ ES6 (ES2015) 時代もグローバル汚染は回避しますが、回避手段が増えています。
42
+
43
+ ```JavaScript
44
+ <script>
45
+ /**
46
+ * (B) ES6 (ES2015) type1
47
+ */
48
+ 'use strict';
49
+ (() => { // ArrowFunction
50
+ function handleClick (event) {
51
+ console.log(event.type);
52
+ }
53
+
54
+ const main = () => {
55
+ this.document.addEventListener('click', handleClick, false);
56
+ };
57
+
58
+ main();
59
+ })();
60
+
61
+ /**
62
+ * (C) ES6 (ES2015) type2
63
+ */
64
+ { // BlockStatement
65
+ const handleClick = function handleClick (event) {
66
+ console.log(event.type);
67
+ };
68
+
69
+ const main = () => {
70
+ this.document.addEventListener('click', handleClick, false);
71
+ };
72
+
73
+ main();
74
+ }
75
+ </script>
76
+ ```
77
+
78
+ いずれも私が気を付けていることは、**main 関数がグローバルコードと同じ this 値を持っていること**です。
79
+ が、これは私の個人的なポリシーであり、標準的な基準があるわけではありません。
80
+
15
81
  Re: Chironian さん