javascriptあれこれ備忘録

javascriptに関する覚え書き。

関数は"first class"オブジェクトである。ファーストクラスだと、

  • 無名リテラルで表現OK
  • 変数に格納OK
  • データ構造に格納OK
  • 関数に引数として渡せる
  • 関数の戻り値にできる
  • 実行時に定義できる
  • 関数名と変数名は無関係

などなど。。。

//無名リテラルで表現OK
function(){    //<--- 名前の無い関数リテラルを宣言
  return "boo";
}

//変数に格納OK
var hoge = function(){ //<--- 変数hogeを宣言し、無名関数で初期化している
  return "boo";
};

//関数名と変数名は無関係
function foo() {}
alert(foo); // 関数名 "foo" を含む文字列をアラートする
var bar = foo;
alert(bar); // アラートする文字列には変わらず関数名 "foo" が含まれている

//実行時に定義できる->つまりクロージャーを作成できる
function hoge(){
  var daba = "Hello";
  return bobo();
  function bobo(){
    return "Hey" + daba;
  }
}

変数の宣言方法
変数はvar キーワードで宣言する。
グローバルスコープにおいて宣言された変数は、グローバルオブジェクトのプロパティとして作成される。
ブラウザの場合、windowオブジェクトのプロパティとなる。
宣言されていない変数にアクセスしようとするとReferenceError 例外が発生する。
初期化されていない変数にはundefinedがセットされる。

関数を定義する3つの方法とそれぞれの違い

//function文で定義(これは関数宣言)
//この場合、関数を定義しているスコープに関数名と同じ名前の変数が作成され、この関数が代入される
function name([param[, param[, ... param]]]) {
   statements
}

//function演算子で定義(これは関数式)
//この場合Functionオブジェクトを返す。nameを指定すれば名前付きのFunctionオブジェクトを返す。
function [name]([param[, param[, ... param]]]) {
   statements
}

//Functionコンストラクターで定義
new Function([param[, param[, ... param]]], functionBody)

//"function"キーワードは、文脈によって、関数宣言にも、関数式にもなる。
//式の一部となっている場合、if文内など、ネストの中にある場合などのばあい、、
//functionキーワードは関数式として構文解析される。
ただし、ブラウザによっては(IE8など)名前付き関数式を関数宣言解釈するものがあるので、注意。

関数には名前を付けることができるが、その名前は自身の関数内からのみ参照可能である。

function something_001(){}
alert(something_001);     //<--- function something_001(){}と表示される

var bobo = function something_002(){};
alert(something_002);     //<--- エラーになる(グローバルスコープからsomething_002にはアクセスできない)

//上のsomething_001の例は、
var something_001 = function something_001(){}
//と同じ。だからエラーにならない。

ホイスティング
あるスコープ内の変数宣言・関数宣言は、その位置に関わらずスコープの先頭に持ち上げられる(ホイスティングという)。
潜在エラーを回避するため、変数宣言はできる限りスコープの先頭で行うのがよい。

var myvar = "my value";
 
(function() {
  console.log(myvar); // undefined
  var myvar = "local value";
})();

hogehoge();
function hogehoge(){
  alert("HOGE----");// HOGE----がアラートされる
}

//さらに、関数宣言は初期化されていない変数宣言をオーバーライドする
var hogehoge;

alert(hogehoge); //<--- function(){〜}がアラートされる

var hogehoge = "hogehoge";

alert(hogehoge); //<--- "hogehoge"がアラートされる

スコープ
javascriptでは、ソースコード内の位置によって変数のスコープが作成される(レキシカルスコープという)。
関数内で宣言された変数のスコープは、関数内のみ。同様に引数のスコープもその関数内のみ。
単なるコードブロックはスコープを作らない。オブジェクトによってスコープが作られる。従って、if文なども同様にスコープを作らない。

var x = 1;
{
  x = 2;
}
console.log(x) //2


//スコープチェーン
あるスコープ内に変数定義が見つからない場合、上位のスコープにさかのぼって変数定義をサーチする。

this 演算子

関数をコールする際に、”."演算子で結びつけられているオブジェクトの参照が、thisに渡される。結びつけられていない場合はグローバルオブジェクトの参照がthisに渡される。
グローバルスコープでのthisは、グローバルオブジェクトの参照を返す。
関数内のthisは、それを利用しているオブジェクトへの参照を返す。

new演算子
new foo(...)の場合、次のステップで演算が行われる:

  1. 新たにfoo.prototypeを継承したオブジェクトが作成される
  2. コンストラクタ関数fooが「指定した引数とthis(<=上で作成されたオブジェクトの参照)」と共に実行される
  3. コンストラクタの返すオブジェクトが演算結果となる。コンストラクタが値を返さない場合(こちらの方が一般的)上で生成されたオブジェクトが演算結果