こちらの質問に回答したのですが、
JavaScript - JSの関数について教えてください。(59737)|teratail
ふと、「名前のある関数式は無名関数なのではないだろうか」という疑問がわきましたので、お教えいただきたく質問いたします。
javascript
1var f = function fn(){}; 2f(); 3fn(); //エラーになる
というように、名前のある関数式は名前空間を占有しないので、無名関数なのでは、と思ったのですが、
javascript
1(function factorial(x){ return (x<=1) ? 1 : x * factorial(x-1) })(num)
というように、自分の名前を参照することはできますので、どちらなのか分からなくなってきました。
ECMA2016の定義を見ると、
14.1.10 Static Semantics: IsAnonymousFunctionDefinition ( production )#
ECMAScript® 2016 Language Specification
というものがあり、この定義ですと、名前のある関数式はAnonymousFunctionDefinitionではないようなのですが、これはこれでまた別の話なような気もしています。
明確な定義や出典が見つからなければ、「自分はこう思う」というようなご意見でもかまいません。よろしくお願いいたします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答6件
0
ベストアンサー
ES6以降では、関数宣言であっても名前が無い関数が書けます。
※ 匿名が可能なのはexport default
を使ってモジュールとして作成した場合のみです。それ以外はエラーになります。
JavaScript
1export default function () { 2 console.log("hoge"); 3}
以上を踏まえて、ECMAScript® 2016 Language Specification(以下、仕様書)を見ながら、解釈していきます。なお、ES6以降はES5以前と内部の仕様が大きく異なります。今回はECMAScript 2016での解釈であって、ES5以前については考察の対象外です。
はじめに「無名関数」の定義をはっきりさせなければなりません。原則、根拠は仕様書から行います。仕様書に明記されていない事柄のみ、計算科学およびプログラミング言語での慣習に基づく判断とします。
####【その1】英語表記との同定
まず、"nameless function"という言葉は一度も仕様書には出てきません。ただ、慣習として、無名関数=匿名関数(anonymous function)とする場合が多い(Wikipeida[ja]:無名関数)ため、仕様書内の"anonymous function"の事を示すとします。
####【その2】用語定義での記載
4.3 Terms and Definitionsでは各用語が定義されていますが、このリストに"anonymous function"はありません。そのため、他の文脈からどのように使われているかで、仕様書の作者がどのような意味で使用したを推定する必要があります。
####【その3】文書内での記述
"anonymous function"は仕様書内で5回現れます。
14.1.3Static Semantics: BoundNames
"*default*"
is used within this specification as a synthetic name for hoistable anonymous functions that are defined using export declarations.
14.4.2 Static Semantics: BoundNames
"*default*"
is used within this specification as a synthetic name for hoistable anonymous functions that are defined using export declarations.
17 ECMAScript Standard Built-in Objects
Every built-in Function object, including constructors, that is not identified as an anonymous function has a
name
property whose value is a String.
Anonymous functions objects that do not have a contextual name associated with them by this specification do not have a
name
own property but inherit thename
property of %FunctionPrototype%.
26.2.2.1.1 Proxy Revocation Functions
A Proxy revocation function is an anonymous function that has the ability to invalidate a specific Proxy object.
それぞれの項目から次のように言えます。
- 名前が無い関数宣言(
export default
でのみ使用可能)は"anonymous function"である。 - 名前が無いジェネレーター宣言(
export default
でのみ使用可能)は"anonymous function"である。 - Proxy無効関数は"anonymous function"である。
三番目の文はビルトイン関数に関してです。
"anonymous function"とされていないコンストラクタを含む全ての関数は、文字列を値とした
name
プロパティを持つ。
四番目の文は何か特定の関数について言っているのでは無く、全ての関数について言及しています。
この仕様書によって文脈的な名前と関連づけられていない"anonymous function"は、自身に
name
プロパティを持たず、Functionのプロトタイプから継承したname
プロパティを持つ。
問題は「この仕様書によって文脈的な名前と関連づけられていない」が"anonymous function"の必要条件なのか十分条件なのかです。名前が関連づけられた"anonymous function"や名前が関連づけられていない非"anonymous function"があるかはわかりません。
####【その4】抽象操作(abstract operation)名での使用
"anonymous function"と名付けられているものに次があります。
14.1.10 Static Semantics: IsAnonymousFunctionDefinition ( production )
これはprudoction
にあたるコード自体(つまり定義の仕方)を検査するためのもので、prudoction
によって生成される物が何かと言うことを検査することではありません。定義としては、IsFunctionDefinitionがtrue、かつ、HasNameがfalseになるときだけ、trueになります。その条件を満たすのか下記です。
- アロー関数(定義): ArrowParameters
=>
ConciseBody - 関数式:
function
(
FormalParameters)
{
FunctionBody}
- ジェネレーター式:
function
*
(
FormalParameters)
{
GeneratorBody}
- クラス式:
class
{
ClassBody}
- 継承ありクラス式:
class
extends
LeftHandSideExpression{
ClassBody}
IsAnonymousFunctionDefinitionの対象となるのは代入の右辺に現れることができる式であるため、**宣言は操作の対象として含まれていません。**つまり、IsAnonymousFunctionDefinitionと宣言は全く無関係であり、対象となっていないため、検査自体ができません。
さらに、このIsAnonymousFunctionDefinitionが具体的にどう使われているかというと、関数が変数に代入されたときに関数のname
プロパティに変数名を入れる必要があるかどうかの判定に使われます(12.15.4 Runtime Semantics: Evaluation)。つまり、IsAnonymousFunctionDefinitionがtrueであっても、最終的に、関数のname
プロパティが設定されている場合があると言うことです。
以上のことから、それぞれの文脈と矛盾無く用語の定義を考えて、私はこのように解釈しました。
- JavaScriptにおける無名関数(匿名関数、nameless function、anonymous function)とは、自身に
name
プロパティを持たない関数、ジェネレーター、アロー関数、クラスである。関数宣言であるとか関数式であるとか関係無い。 - JavaScriptにおける無名関数定義(匿名関数定義、nameless function definition、anonymous function definition)とは、名前が指定されていない関数宣言、ジェネレーター宣言、クラス宣言、関数式、ジェネレーター式、クラス式、アロー関数(定義)である。その後の変数の代入等により、生成された関数オブジェクトが無名関数では無くなる場合があり得る。
つまり、ECMAScirpt 2016においては、
JavaScript
1var hoge = function() { 2 console.log("hoge"); 3};
は、無名関数定義を使用しているが、生成される関数は無名関数では無い、というふうに解釈します。あくまで私の解釈であり、仕様書には用語定義がないため、絶対的に正しいと保証する物ではありません。
投稿2016/12/24 09:44
編集2016/12/24 13:43総合スコア21735
0
Function#name (ECMAScript 2016 / ECMAScript 7)
ES2016 には次の一文があります。
Anonymous functions objects that do not have a contextual name associated with them by this specification do not have a name own property but inherit the
name
property of%FunctionPrototype%
.
機械翻訳「この仕様で関連付けられたコンテキスト名を持たない匿名関数オブジェクト(Anonymous functions objects)は独自のプロパティを持たず、%FunctionPrototype%
の name
プロパティを継承します。」
従って、Function#name
を利用する事でそれが匿名関数(Anonymous function)か識別する事が可能です。
JavaScript
1function foo () {} // Function Declaration (関数宣言) 2console.log(foo.name); // "foo" (Named Function Declaration) ※名前付き関数宣言 3 4console.log(function (){}.name); // "" (Anonymous Function Expression) ※匿名関数式 5console.log(function bar (){}.name); // "bar" (Named Function Expression) ※名前付き関数式 6console.log((()=>{}).name); // "bar" (Anonymous Arrow Function) ※匿名アロー関数 7 8var piyo = ()=>{}; // Arrow Function 9console.log(piyo.name); // "piyo" (Named Arrow Function) ※名前付きアロー関数 (厳密には、アロー関数自身に名前があるわけではありませんが…)
一般呼称としての無名関数 (Nameless Function)
(私の観測範囲ではという前提付きですが)
一般に「無名関数」と呼ぶときには関数式と関数宣言を区別する為に使われる事が多いように感じています。
(使用例1) addEventListener
の第二引数は関数宣言した変数を入れる方法と無名関数を入れる方法があります。
(使用例2) setTimeout
の第一引数には無名関数を入れましょう。
いずれも「関数式」に置き換えても意味が通りますし、「無名関数式」である必然性はありません。
名前付き関数式にすれば再帰呼び出しも可能です。
JavaScript
1setTimeout(function sample (i) { 2 console.log(i); 3 setTimeout(sample, 100, ++i); 4}, 100, 0);
それでも「無名関数」という呼称がよく使われるのは「関数式」に馴染みがないからだと思います。
一般人からすれば「関数式 === 無名関数」であり、名前付き関数式の存在は知らない人が大半です。
ですので、「無名関数」という表現が使われた時には文脈的にそれが「関数式」を表しているのか、「無名関数式」を表しているのか読み取る必要があると考えます。
私は表現のゆらぎが嫌いなので必要であれば、「無名関数式」と書いています。
初心者が「無名関数」を理解させようとすると著者や文脈によって意味が変わる事で混乱させてしまいます。
「無名関数」は一種のバズワードだと思います。
raccy さんが仰るように仕様書の用語定義に「Anonymous Function(匿名関数)」「Nameless Function(無名関数)」はない為、積極的に使うべき用語ではないと思います。
(余談) IE8- は名前付き関数式を関数宣言としても扱う
JavaScript
1var f = function fn(){}; 2f(); 3fn(); //エラーになる
余談ですが、IE8- では上記コードはエラーにならず、関数呼び出し出来ます。
ECMAScript 上はエラーになるはずで IE8- のバグなのですが、ふと思い出したので参考まで。
Re: Lhankor_Mhy さん
投稿2016/12/24 12:40
編集2016/12/24 12:46総合スコア18162
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/12/25 13:48
0
無名関数に名前をつけたもの(名前付き無名関数[named anonymous function])という認識でよろしいかと思います。
無名関数それ自身で再帰ができるようになります。
投稿2016/12/24 06:50
退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/12/24 07:26
退会済みユーザー
2016/12/24 07:34
2016/12/24 08:11
0
そもそも、「無名関数」という区分自体がJavaScriptになじまないと個人的には思います。
コードで示しますが、
var foo = { bar: function(){ /* その1 */ } } foo.bar(); foo.baz = function(){ /* その2 */ }; var tmp = function(){ /* その3 */ }; foo.quz = tmp;
このように、「リテラルに名前を書かなかった関数」が「オブジェクトのメソッドになる」ことすらごく普通にあるような言語です。
投稿2016/12/24 08:17
総合スコア145183
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/12/24 08:46
2016/12/24 08:55
2016/12/24 09:11
0
###※以下は私の考え方です
あんまり深く考えたことがないですね。。
(その域まで達していない(恥)
javascriptで表現すると、
var f = function fn(){};
は無名関数 + 関数名
var f = function (){};
は無名関数
(function factorial(x){ return (x<=1) ? 1 : x * factorial(x-1) })(num)
は即時関数 + 関数名
(function (x){ return (x<=1) ? 1 : x * factorial(x-1) })(num)
は即時関数
function
で定義しているものは関数(関数定義)
つまり、
var f = function fn(){};
は無名関数という事かなと考えます。
文献はないですが、
上記のように解釈しています。
投稿2016/12/24 06:56
総合スコア882
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
あなたはたぶん、「関数宣言文」が分かっていないのだと思います。
以下の「関数宣言文」は
function fn() {}
var window.fn = function fn() {};
と等価です(ブラウザで実行するJavaScriptの場合に限定)。
「関数宣言文」は暗黙的に、グローバルオブジェックトのプロパティに関数オブジェクトを代入しているのです。それを省略した書き方に過ぎないのです。ただそれだけですよ。
※そんな言葉はない気がしますがこのページでは、名前がある関数を便宜的に「有名関数」と呼ぶことにします。
有名関数を代入したら代入式です。関数宣言文ではないのでグローバルオブジェックトのプロパティに設定されないので、呼び出せないだけです。
以下のサンプルコードを実行してみてください。
javascript
1// 関数宣言文 2function fn1() { 3 console.log(this === window); 4 console.log(this.fn1.name); 5} 6 7// 有名関数の代入式 8var f2 = function fn2() { 9 console.log(this === window); 10 console.log(this.f2.name); 11}; 12 13// 無名関数の代入式 14var f3 = function() { 15 console.log(this === window); 16 console.log(this.f3.name); 17}; 18 19fn1(); 20f2(); 21f3();
thisはwindowを指し示すのです。ですから当然、「window.fn1();」などと書いても呼び出せます。
無名関数は名前が定義されていないというだけです。変数f3に代入している関数は、無名関数でも何度も呼び出せるのです。nameを確認すると設定されていないことが分かります。確かに無名なのです。少なくともFirefoxとEdgeではそうなります。ですので呼び出せるかどうかと有名か無名かは関係のない概念です。区別しましょう。
※ただし、Chromeで実行すると、変数名が設定されています。これはChromeの独自仕様だと思います。名前は設定されないのが本来の仕様として正しいと思います。
名前のある関数式は名前空間を占有しないので、無名関数なのでは、と思ったのですが、
無名かどうかは名前があるかどうかです。名前空間がどうとかいう話は関係ありません。
投稿2016/12/24 09:35
総合スコア902
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/12/24 12:58
2016/12/24 14:34
2016/12/25 00:08 編集
2016/12/25 04:03
2016/12/25 05:24
2016/12/25 06:55 編集
2016/12/25 18:25
2016/12/26 03:45 編集
2016/12/26 03:43
2016/12/27 16:04
2016/12/27 16:30
2016/12/28 00:43
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/12/25 04:53
2016/12/25 05:11