読者です 読者をやめる 読者になる 読者になる

リア充爆発日記

You don't even know what ria-ju really is.

Javascript初心者に初心者++程度の自分が言語仕様を説明したときのメモ(第一回)

なんらかのクラスベース言語の経験がある人向けのJavascript勉強会の第一回メモ。

Javascriptはプロトタイプベースのオブジェクト指向言語

クラスベースではない、ということだけ覚えておいて先に進む。

データ型

プリミティブとオブジェクト型の2種類ある。

  • プリミティブ
    • string:文字列
    • number:数値
    • boolean:真偽値
    • undefined:undefined
    • null:null
  • オブジェクト
    • object:オブジェクト
    • function:関数オブジェクト

オブジェクト

  • 関数オブジェクト以外のすべてのオブジェクトはHashmap
 var foo = {
    name: "Taro",
    sayName: function () {
       alert(this.name);
    }
 }

プリミティブ型とビルトインオブジェクト

プリミティブのstring, number, booleanはそれぞれ対応する便利関数とプロパティ付きのビルトインオブジェクト(String, Number, Boolean)があり、それらは明示的にオブジェクト生成しなくても呼び出せば暗黙的にオブジェクト変換されて使える。

 var foo = "hello";
 f.charAt(0); // "h" ※ "hello".charAt(0)でも同じ
 foo.length; // 5 ※関数じゃなくて、Stringオブジェクトが持つlengthというプロパティへのアクセス

「暗黙的に変換される」のであって、プリミティブはオブジェクトではない(あたりまえ)。これは型を確認するtypeof演算子を使うとわかる。

var a = "hello";
var b = new String("hello"); // String {0: "h", 1: "e", 2: "l", 3: "l", 4: "o", length: 5}

typeof(a) // "string"
typeof(b) // "object"

関数オブジェクト

すべての関数はFunctionオブジェクト。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function

関数定義

関数定義は関数宣言(function文)と関数式(function演算子)の2通りのやり方がある。

  • 関数宣言
function name([param[, param[, ... param]]]) {
   statements
}
  • 関数式
function [name]([param] [, param] [..., param]) {
   statements
}

さらにFunctionオブジェクトのコンストラクタを使った方式も交えて、それぞれの相違点を確認する。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope#Function_constructor_vs._function_declaration_vs._function_expression

Functionオブジェクトのコンストラクタ
var multiply = new Function("x", "y", "return x * y;");
関数宣言(function文)
function multiply(x, y) {
   return x * y;
}
関数式(function演算子
var multiply = function(x, y) {
   return x * y;
};
関数式で名前付きの関数を変数に代入
var multiply = function func_name(x, y) {
   return x * y;
};
  • 関数名は変更できない
  • 関数が代入された変数は、再代入できる
  • 関数を代入した変数名と、代入された関数名は何の関係もない
  • 関数名は、関数内でのみ、参照できる
var y = function x() {};
alert(x); // エラー
  • 関数宣言は、宣言時に関数名と同名の変数が作られるので、関数宣言したスコープ内で参照できる
function x() {}
alert(x); // エラーにならない
  • Functionコンストラクタで定義された関数は名前を持たないが、SpiderMonkeyエンジン(Firefoxなど)では、"anonymous"という名前が付いているように見える。(が、実際には持っていない。)
alert(new Function()) // function anonymous() {}
var foo = new Function("alert(anonymous);");
foo(); // エラー
  • 関数宣言で定義された関数は、宣言前に使うことができる
foo(); // alerts FOO!
function foo() {
   alert('FOO!');
}
  • 関数宣言や関数式で定義された関数は、一度しかパースされないが、Functionコンストラクタで定義された関数は、それが参照される度にパースされる。ので、必要がなければFunctionコンストラクタは使うべきでない。ちなみに、Functionコンストラクタ内でネストされた関数宣言や関数式は一度しかパースされない。
var foo = new Function("alert(bar)");
foo(); // コンストラクタの引数が再パースされる
// ============
var foo = (new Function("var bar = \'FOO!\';\nreturn(function() {\n\talert(bar);\n});"))();
foo(); // 再パースされない 

これをどういうときに使うのかまったくわからん。
2014/05/14 追記)ここの記述についてコメントに「引数は再度パースされたりしない」と書いてもらったんだけど、上述のMDNのFunctionのページに"Functions defined by function expressions and function declarations are parsed only once, while those defined by the Function constructor are not. That is, the function body string passed to the Function constructor must be parsed every time it is evaluated."と書いてあったのでそう書いた。今のところコメントを書いてくれた人が間違っているのか、ぼくの何かが間違っているのか、そのどちらでもない何らかの相違なのか判別つかないのでこのままにしておきます。


とりあえず、このくらいにしておこうっと。。
2回めはnewとかprototypeチェーンかなぁ。