@uents blog

Code wins arguments.

JavaScriptでHello Worldと関数定義

久しぶりのブログ。

仕事でJavaScriptを使うことになったので、サイ本第5版とJavaScript: The Good Partsで勉強し直している。

というわけで、最近あまり見ないけど、手始めにHello Worldをやってみた。

3つの関数定義

console.log()だけでは面白くないので、関数定義してみた。

// function文                                                                                                                                                 
function main1 () {
    console.log("#1 Hello, World");
}

// Functionコンストラクタ                                                                                                                                         
var main2 = new Function("console.log(\"#2 Hello, World\");");

// 関数リテラル                                                                                                                                                   
var main3 = function () {
    console.log("#3 Hello, World");
}

JavaScriptには3種類の関数定義がある。

  • function文: 名前付きの関数オブジェクトを生成
  • Functionコンストラクタ: 常に新しい匿名関数オブジェクトを生成
  • 関数リテラル: 匿名関数オブジェクトを生成 (常に新しいとは限らない)

nodeで実行してみる。

% node
> .load hello.js
> main1();
#1 Hello, World
undefined
> main2();
#2 Hello, World
undefined
> main3();
#3 Hello, World
undefined

undefinedと出ているのは関数の返値。returnを宣言していないとデフォルトでundefinedが返る。

関数名/変数名に対しconsole.log()を実行してみる。

> console.log(main1);
[Function: main1]
undefined
> console.log(main2);
[Function]
undefined
> console.log(main3);
[Function]
undefined

main1は名前付きの関数であるのに対し、main2/main3の関数は匿名関数であることが分かる。
(main2/main3は匿名関数を格納した変数の名前)

Functionコンストラクタと関数リテラルの違い

サイ本に詳しく書いているけど、

  • Functionコンストラクタは使うたびに関数の本体が解釈され、新しい関数オブジェクトが生成される。それに対し、関数リテラルは関数やループの中で毎回コンパイルされるわけでもなければ、関数リテラルを実行するたびに新しい関数オブジェクトが生成されるわけでもない
  • Functionコンストラクタが生成する関数は静的スコープ(lexical scope)を使わない。常にトップレベルのスコープ

後者のスコープの違いについて試してみる。

var str = "Global";

(function() {
    var str = "Local";

    // Functionコンストラクタ                                                                                                                       
    var hello1 = new Function("console.log(\"#1 Hello, \" + str);");

    // 関数リテラル                                                                                                                               
    var hello2 = function() {
        console.log("#2 Hello, " + str);
    };

    hello1();
    hello2();
})();

nodeでの実行結果。

> .load hello2.js
#1 Hello, Global
#2 Hello, Local

これらの違いのため一般的には関数リテラルが使われるらしい。

関数定義だけでもなかなか奥が深くて面白い。

JavaScript 第6版

JavaScript 第6版

JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス

JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス