PHP, js, rubyでの宣言と定義の違いを教えてください!!!!
下のサイトを読んだのですが、あまり内容がわからなくて・・・
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q13120175843
https://msdn.microsoft.com/ja-jp/library/0e5kx78b.aspx
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
ECMAScript 2017
原則として、この回答は ECMAScript 2017 の仕様を元にしています。
ECMAScript 2017 は JavaScript の根幹となる標準仕様です。
宣言 (Declaration)
ECMAScript 2017 で「宣言 (Declaration)」と名の付く用語をリストアップします。
- 13 ECMAScript Language: Statements and Declarations - ECMAScript® 2017 Language Specification
- 13.3.1 Let and Const Declarations - ECMAScript® 2017 Language Specification
- 13.3.2 Variable Statement - ECMAScript® 2017 Language Specification
上記節に出てくる Syntax (文法) を日本語に翻訳します。
- 宣言 (Declaration)
- 巻き上げ可能な宣言 (HoistableDeclaration)
- Class 宣言 (ClassDeclaration)
- レキシカル宣言 (LexicalDeclaration)
- 関数宣言 (FunctionDeclaration)
- ジェネレータ宣言 (GeneratorDeclaration)
- 非同期関数宣言 (AsyncFunctionDeclaration)
- 変数宣言 (VariableDeclaration)
ここで一つの疑問が浮かびます。
宣言とは、「誰が何に向かって宣言している」のでしょうか。
この場合は「コードがパーサに向かって宣言している」といえます。
宣言はコードを構成する部品に過ぎず、中にはそれのみでは valid なコードになれないもの(例: VariableDeclaration)もあります。
パーサはあらゆる宣言を解釈して、コードを実行可能な状態にコンパイルします。
定義 (Definition)
宣言と同様、ECMAScript 2017 で「定義 (Definition)」と名の付く用語をリストアップします。
定義は宣言よりも広い意味となります。
- 14.1 Function Definitions - ECMAScript® 2017 Language Specification
- 14.2 Arrow Function Definitions - ECMAScript® 2017 Language Specification
- 14.3 Method Definitions - ECMAScript® 2017 Language Specification
- 14.4 Generator Function Definitions - ECMAScript® 2017 Language Specification
- 14.5 Class Definitions - ECMAScript® 2017 Language Specification
- 14.6 Async Function Definitions - ECMAScript® 2017 Language Specification
- 14.7 Async Arrow Function Definitions - ECMAScript® 2017 Language Specification
上記タイトルを日本語に翻訳します。
- 関数定義 (Function Definitions)
- アロー関数定義 (Arrow Function Definitions)
- メソッド定義 (Method Definitions)
- ジェネレータ関数定義 (Generator Function Definitions)
- Class 定義 (Class Definition)
- 非同期関数定義 (Async Function Definitions)
- 非同期アロー関数定義 (Async Arrow Function Definitions)
定義は宣言よりも総合的な意味合いが強いように読めます。
宣言という言葉は Syntax 上に出てきますが、Definition が出てくるケースはほとんどありません(ゼロではありませんが、少なくとも上にあげたものにはありません)。
詳細は後述しますが、宣言(Declaration)という構成要素をパーサが解釈(パース)し、関数や変数が定義される事を表しているのだと思います。
宣言する (declare)
ECMAScript syntax intentionally resembles Java syntax. ECMAScript syntax is relaxed to enable it to serve as an easy-to-use scripting language. For example, a variable is not required to have its type declared nor are types associated with properties, and defined functions are not required to have their declarations appear textually before calls to them.
機械翻訳「ECMAScript構文は意図的にJava構文に似ています。 ECMAScript構文は、使いやすいスクリプト言語として機能するように緩和されています。 たとえば、変数の型宣言やプロパティに関連する型の必要はなく、定義された関数の宣言を呼び出す前にテキストで表示する必要はありません。」
"定義された「関数の宣言」を呼び出す" とあります。
これは下記リンク先の Syntax で定義されている FunctionDeclaration (関数宣言) を表しており、「定義された FunctionDeclaration を呼び出す」と読み替えることが出来ます。
ここから読み取れるのは、宣言してから定義するという順番性です。
「関数宣言を定義する」とは、関数を「宣言」する事で「定義」が完了する事を表しています。
ですので、「関数定義を宣言する」のように逆の順番で表現することは出来ません。
定義する (define)
A var statement declares variables that are scoped to the running execution context's VariableEnvironment.
機械翻訳「var 文(statement)は、実行中の実行コンテキストのVariableEnvironmentにスコープされている変数を宣言します(declares)。」
これは VariableStatement
という変数文を解釈⇒実行する過程の一文です。
変数文は Syntax 上の VariableDeclaration
(変数宣言)を解釈します。
JavaScript
1var a, b; // 変数文全体で VariableStatement を表す。a, b がそれぞれ VariableDeclaration を表し、複数の変数宣言を解釈できる。
Within the scope of any VariableEnvironment a common BindingIdentifier may appear in more than one VariableDeclaration but those declarations collective define only one variable.
機械翻訳「VariableEnvironmentのスコープ内では、共通のBindingIdentifierが複数のVariableDeclarationに現れることがありますが、それらの宣言は1つの変数のみを定義します。」
細かな説明は省きますが、重要なのは「宣言を解釈して定義する」という順番性です。
JavaScript
1var a = 1, b = 2;
「a = 1
という変数 a
の宣言」と「b = 2
という変数 b
の宣言」を解釈し、VariableStatement
として認められる事で 変数 a, b が定義される、となります。
JavaScript
1var a = 1, b = !!!; // SyntaxError: Unexpected token ;
このコードは変数 a
を宣言しましたが、変数 b
の宣言に失敗している為、結果として変数 a
, b
は定義されていません。
ユーザ定義関数(User-defined function)
ユーザ定義関数(User-defined function) はECMAScript 2017 に存在しない用語ですが、比較的読む見る用語の為、触れておきます。
下記の関数 foo のようなコード制作者が定義した任意の関数を「ユーザ定義関数」と呼びます。
JavaScript
1function foo () { 2 console.log(foo); 3}
コード制作者は上記コードを「関数 foo を定義する」と表現します。
関数宣言(FunctionDeclaration
)は関数を定義する上で最上位の Syntax なので、「関数 foo を宣言する」と表現しても概ね通じますが、最終的に関数 foo が実体化された事を強調するには「定義する」の方が好ましいといえます。
また、「ユーザ定義関数(User-defined function)」という言葉はありますが、「ユーザ宣言関数(user-declared function)」という言葉は読んだ覚えがありません。
これも宣言してから定義するという順番性を表しているのかもしれません。
関数宣言(FunctionDeclaration)と関数式(FunctionExpression)
上記リンク先では、大別して次の2つの Syntax が定義されています。
- 関数宣言 (FunctionDeclaration)
- 関数式 (FunctionExpression)
関数定義は関数宣言と関数式を総合した名称です。
従って、「関数定義 === 関数宣言」ではありませんし、関数宣言と関数式は別個の存在として定義されています。
JavaScript
1function foo () { console.log('foo'); }
上記コードは関数宣言(FunctionDeclaration)を定義しています。
JavaScript
1(function bar () { 2 console.log('bar'); 3}());
上記コードは関数式(FunctionExpression)を定義しています。
JavaScript
1var piyo = function piyo () { 2 console.log('piyo'); 3};
上記コードは関数式を定義した後に変数 piyo を定義しています。
「変数文」と「関数式」の定義が独立している点に注意して下さい。
厳密には、変数文の処理過程で変数宣言が行われている事になります(詳細は「定義する」の節を参照して下さい)。
- 関数式 piyo を定義する
- 変数 piyo を宣言する
- 変数 piyo を定義する
更新履歴
- 2017/08/21 11:41 「関数宣言(FunctionDeclaration)と関数定義(Function Definitions)」の節を追記
- 2017/08/25 12:38 見出しを修正。関数宣言(FunctionDeclaration)と関数定義(Function Definitions) -> 関数宣言(FunctionDeclaration)と関数式(FunctionExpression)
Re: COCO-nuts さん
投稿2017/08/20 02:52
編集2017/08/25 03:39総合スコア18189
0
宣言(declaration)と定義(definition)という言葉について何を意味するのかは言語によっては特殊な意味を持つも事があります。ですが、ほとんどの場合はC言語での意味とほぼ同じになるでしょうから、C言語での宣言と定義が意味するところが、各言語においてどうなるかを説明していきます。
####C言語での宣言と定義
C言語は宣言と定義を分けて書くことができる言語です。分けて書くことができない言語も存在しますし、C言語であっても宣言と定義が兼ねる場合があります。この点はご注意ください。
宣言は「ある識別子(identifier)はこういう類いの物である」と宣言することです。識別子というのは変数名とか関数名とか型名とかの事です。プログラムの中でa
という識別子を使うとき、
C
1int a(int);
と書いてあったとします。これは関数の宣言であり、「a
はint一つを引数にしてintを返す関数である」ということを宣言します。この時点ではどのような関数であるかはわかりません。しかし、関数であることはわかっているので、この後のコードではa(42)
と言った形でa
を関数として使用することができます。同じように、これはintの変数だと言った宣言が可能です。
対して、定義は「ある識別子(identifier)は具体的にこういう中身である」と定義することです。先ほどのa
を定義してみましょう。
C
1int a(int x) 2{ 3 return x + 1; 4}
宣言だけではa
は関数であるということしかわかりませんでした。しかし、定義によってどんな動作をする関数であるかと言うことが定義されます。上の例では引数に1足した数を返す関数という定義です。コードの中でa(42)
等と書かれた場合は、この定義に従って関数の評価が行われ、43を返す事でしょう。
注意して欲しいのは、定義は宣言も兼ねられると言うことです。最初の宣言を書かずに二番目の定義だけを書いたら、定義の部分で宣言がされたと見なされます。宣言と同じように、この後のコードでa
を使うことが可能です。
逆に宣言と定義を分離できない場合もあります。例えば、型を定義するtypedefは宣言だけを行うことはできません。T
は型ですと宣言すると同時に、具体的に○○と言う型ですと定義する必要があります。
なお、変数の定義についてですが、変数はローカル変数なのかグローバル変数なのかといった書き方によって宣言が定義を兼ねる場合もあれば、別々の場合もあり、複雑なので具体的には言及しません。ただ、変数の場合はメモリ上に確保されるところをもって定義としているようです。
以上がC言語の場合ですが、これとほぼ同じなのはC++ぐらいです。他の言語では宣言と定義がわかれていない場合があります。
####PHPでの宣言と定義
PHPについては、細かい仕様を語れるほど詳しくないので、他の人に説明を任せます。ごめんなさい。
####ECMAScript(JavaScript)での宣言と定義
ECMAScriptの関数もクラスも変数も宣言と定義を兼ねます。先行して宣言だけを行うことはできません。
JavaScript
1function a(x) { 2 return x + 1; 3}
このコードを定義の部分を外して書くことができないと言うことです。
人によっては次のコードは宣言と定義がわかれていると言うかも知れません。
JavaScript
1var a; 2a = function (x) { 3 return x + 1; 4};
このコードの正しい解釈は、a
という変数が定義され(この時点ではa
にはundefinedが入っています)、その後にa
という変数に関数が代入されて、a
は関数として使用できるようになったと言うことに過ぎません。a
が先行して宣言されたわけではないのです。
なお、仕様上は、章の題名には「Function Definitions(関数定義)」という言葉を使いながら、文法(syntax)では「FunctionDeclaration(関数宣言)」という言葉を使っています。仕様上の文法では関数宣言という名前ですが、実際は具体的な中身が必ず存在するため、最初に述べたC言語での意味での定義がされていると言って差し支えありありません。**これは、ECMAScriptの仕様書上の用語として「宣言」と「定義」がどうなっているとかはまた別の話であり、決して混同しないでください。**もし、混乱してしまったのであれば、私の書き方が悪かったのだと思われますので、文章力に不足があり、申し訳ありません。仕様書の「宣言」と「定義」について知りたい場合は、think49さんの回答が参考になりますから、そちらを読んでください。この回答をいくら読んでも、仕様上の意味での解釈については一切助けにはなりません。
では、ECMAScriptには定義が無い宣言が無いのかというとそうではありません。importとexportがあります。importではこの外部ファイルをインポートしますという宣言だけです。具体的な中身は外部ファイルに書いてあり、importで定義しているわけではありません。exportでは具体的な中身を書くこともできますが、名前だけ指定してexportすることも可能です。つまり、この変数や関数はエクスポートしますと宣言するだけで、その中身は別の所に書いてあると言うことができます。
####Rubyでの宣言と定義
Rubyも宣言と定義を分けて書くことはできず、全てが宣言と定義を兼ねます。
Ruby
1def a(x) 2 x + 1 3end
a
はメソッドとして定義されましたが、メソッドであることを前もって宣言するような書き方はありません。必ず、具体的な中身(何もしないという空の場合もあり得る)が定義される必要があります。
クラスについては次のようにできるから、分けて書けると指摘する人もいるかも知れません。
Ruby
1A = Class.new 2class A 3 def initialize(x) 4 @x = x 5 end 6 def plus_one 7 @x + 1 8 end 9end
最初にクラスA
については何も中身が無いClassオブジェクトとして作成しました。これは宣言と言えるのでしょうか?いいえ、言えません。具体的にClassのオブジェクトとして生成しているからです。Rubyはオープンクラスと言いわれる後からクラスの中身を実装できる仕組みであるため、後から定義されると言うより、定義が追加で変わっていくと言うだけに過ぎません。最初が定義を意味しないわけではありません。
動的な言語(プログラムの途中で、識別子の意味が動的に変わっていく言語、ECMAScriptとかRubyとか)においては、宣言と定義は一緒の場合が多いように思えます。でも、静的な言語(コンパイル時に、識別子の意味が静的に決定される言語、JavaとかC#とか)であっても、最近の言語は一緒の場合が多いように思えます。宣言と定義の分離は、マシンの性能もコンパイラの品質も貧弱な時代に、静的な言語でコンパイルするための助けになるという意味では有用だったのかも知れませんが、現在においては、単に面倒なだけとされて、廃れた手法になっていっているのかも知れません。
最後に、上では関数の宣言と定義だけで、変数については、少しぼかした表現で、詳しく書いていません。C言語上では、その変数の実体が作られるところ(メモリ領域が確保されるところ)が定義になるのですが、細かく言うとさらに倍の内容になりますので、省いています。PHPのglobalキーワードが変数で宣言と定義がわかれている例になるのですが、PHPについては全てを語るほど詳しくないと言うこともあり、触れていませんでした。
また、もう一つぼかして書いていることで「関数が定義される」と「作成された関数が入っている変数が定義される」の(動作の違いでは無く)意味的な違いを詳しく解説していません。申し訳ありませんが、そこまで話をしてしまうと、どんどん話がずれて言ってしまうので、避けてしまいました。どこかで機会があれば、網羅的に宣言と定義について、記事を書きたいとは思いますが、ここでの回答はここまでとさせていただきます。
投稿2017/08/19 11:19
編集2017/08/25 10:48総合スコア21737
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/08/21 02:45 編集
2017/08/21 09:43 編集
2017/08/22 16:24
2017/08/22 22:04
2017/08/25 03:30 編集
2017/08/25 11:02 編集
0
まず1つ言えば、言語によって対応する言葉が違ってきます。
C言語では(MSDNを見ての通り定義でない宣言があるので)「宣言」と「定義」を峻別する必要が生じますが、ここで上げた3つの言語は、「中身のない関数の宣言だけ」とか「他のファイルで定義されたものを参照するだけの宣言」が存在しないので、変数や型について「定義」や「宣言」という言葉を区別する必要がありません。
ただし、JavaScriptでの'use strict';
やPHPのdeclare
などは、プログラム内に現れる変数や型と関連を持たずに動作を変えるものですので、「宣言」と呼ばれます。
投稿2017/08/19 10:55
総合スコア145930
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。