JavaScript Gardenの読書メモ
2011/02/12(土) 17:09 Javascript親記事へこのエントリーをはてなブックマークに追加

JavaScript Gardenを読んでいたときのメモ
Tweetsの方のログはTogetter - 「JavaScript Gardenの読書会」

感想

まず発見したときにサイドバーのデザインが綺麗だなと思った。また文章内でちゃんと内部リンクが貼ってあってとても見やすい作りになっている。
内容もそこまで難しい書き方はしてないので何とか読める。またコード(or 文字)で書くようにしているのかは知らないけど、画像を一切使わずにprototypeとかをちゃんと説明できていて凄いと思った。
かなり仕様も囓ってる感じの人が書いてて、noteにES5の時についてなども触れられていてかなり細かいとこも書かれていた。難易度的にはJavaScript Patternsと同じくらいだと思うけど、とてもいい文章をWebで公開してくれているので是非読んでおくべきだと思う。
著者であるIvo Wetzel (Writing)とZhang Yi Jiang (Design)に感謝を。
JavaScript Garden
http://bonsaiden.github.com/JavaScript-Garden/

Objects

JavaScriptではnullとundefined以外はオブジェクトのように動いてる。
false.toString() // 'false'
[1, 2, 3].toString(); // '1,2,3'

function Foo(){}
Foo.bar = 1;
Foo.bar; // 1
ただし、数値だけは
2.toString(); // raises SyntaxError
のようになる。それは.を小数点と理解してしまうため。
これを回避する方法はいくつかある
2..toString(); // 2番目の.がドット演算子として認識される。
2 .toString(); // note the space 
(2).toString(); // 2 is evaluated first
二番目は数値とドットの間にスペースを空けるのが正解。

Objects as a data type

JavaScriptのオブジェクトはハッシュマップ。
波括弧{}はプレーンなオブジェクトを作り、それはObject.prototypeから継承している。
まだhasOwnPropertyでかかるもの(自分自身のプロパティ)は持ってない。

Accessing properties

var foo = {name: 'Kitten'}
foo.name; // ドット表記法
foo['name']; // ブラケット表記法

var get = 'name';
foo[get]; // kitten - ブラケット表記法は変数を使える

foo.1234; // SyntaxError
foo['1234']; // works
オブジェクトのプロパティのアクセス方法は2つあって、ドット表記法かブラケット表記法が使える。2つの違いとしてブラケット表記法は動的に設定できることと、構文エラーとなってしまう名前も使用できる

Deleting properties

オブジェクトのプロパティを削除する唯一の方法はdelete演算子を使用すること。
プロパティにundefined や null を入れてもキーは削除されず、値が変わるだけです。(GCとかで消えるかもしれないけど)
この二つの違いがわかる例
barにundefined, fooにnullを入れているがkeyが残っているのでbar undefined, foo nullというアウトプットになる。bazはdeleteされているのでそもそも出てこなくなる。
var obj = {
    bar: 1,
    foo: 2,
    baz: 3
};
obj.bar = undefined;
obj.foo = null;
delete obj.baz;

for(var i in obj) {
    if (obj.hasOwnProperty(i)) {
        console.log(i, '' + obj[i]);
    }
}

Notation of keys

JavaScriptの予約語をキーとして使うとエラーになる。(ES5以降とかブラウザによる)
まあどっちにしても予約語をキーに使わない方がいい。strict modeだと予約語も増える


strictに対応しているようなengineならIdentifierNameにも対応している
Twitter / utatane: @azu_re strictで予約語増えますけど, ...




var test = {
    'case': 'I am a keyword so I must be notated as a string',
    delete: 'I am a keyword too so me' // raises SyntaxError
};

The prototype

JavaScriptではprototypicalが使われています。プロトタイプ継承はclassic model(クラス)より強力。二つの違いを示すものとしてプロトタイプチェーンと呼ばれる継承があります。
function Foo() {
    this.value = 42;
}
Foo.prototype = {
    method: function() {}
};

function Bar() {}

// Set Bar's prototype to the prototype object of Foo
Bar.prototype = Foo.prototype;

var test = new Bar() // create a new bar instance

// The resulting プロトタイプチェーン
Object.prototype: {toString: ... /* etc. */};
    Foo.prototype: {method: ...};
        Bar.prototype: Foo.prototype
            Bar.method()

Property lookup

オブジェクトのプロパティにアクセスしたときにJavaScriptではその名前が見つかるまでプロトタイプチェーンを探索する。最後のObject.prototypeまでいって見つからなかったときはundefinedを返します。

The prototype property

prototypeプロパティはjs側によってプロトタイプチェーンを構築するために使われますが、こちら側で任意の値を設定することも可能です。
prototypeプロパティにプリミティブな値を入れた場合は単純に無視されます。
function Foo() {}
Foo.prototype = 1; // no effect
一方オブジェクトを割り当てた場合は動的にプロトタイプチェーンを構築できます。
function Foo() {
    this.value = 42;
}
Foo.prototype = {
    method: function() {}
};

function Bar() {}

Bar.prototype = new Foo();
var boo = new Bar();

// Resulting prototype chain
Object.prototype: {toString: ... /* etc. */};
    Foo.prototype: {method: ...};
        [Foo Instance]: {value: 42};
            Bar.prototype: [Foo Instance]
                Bar.method()
このようにBar.prototypeはFooのインスタンスを示すようになります。

Performance

プロトタイプチェーンの特性上、パフォーマンスに影響を与える可能性もあります。
また存在しないプロパティにアクセス使用とした場合は常にプロトタイプチェーンを最後まで探索してしまうでしょう。また列挙を行う際にもプロトタイプチェーンを探索してしまう。(いわゆるプロトタイプ汚染されていると困る)

Extension of native prototypes

頻繁にある間違いはObject.prototypeを拡張してしまう事です。
このテクニックはMonkey patchと呼ばれ、カプセル化を壊します。
Object.prototypeを拡張していい、唯一の場合はJavaScriptの新しいバージョンで追加された機能をバックポートする際だけです。
これを行っていい条件は下記にでも
ネイティブのprototypeを拡張していいのは新しいJavaScript機能との互換性がある場合のみにしておくべきです。

hasOwnProperty

hasOwnPropertyはプロトタイプチェーンを探索せずにそのオブジェクトが持っているプロパティなのかをチェックするメソッドです。
// Poisoning Object.prototype
Object.prototype.bar = 1; 
var foo = {goo: undefined};

foo.bar; // 1
'bar' in foo; // true - こっちはプロトタイプチェーンを探索する
// foo自体が持っているプロパティかどうか
foo.hasOwnProperty('bar'); // false
foo.hasOwnProperty('goo'); // true
いわゆるfor-inループと組み合わせて、プロトタイプ汚染されていた場合も列挙できるように使われていたりする。
パフォーマンスについては下記

Functions

function declaration - 関数宣言
function foo() {}
function expression - 関数式
var foo = function() {};
二つの違いはパースのステージで定義されてるのか、実行のステージで定義されるのかである。

Named function expression

名前付き関数式での名前はローカルスコープのみで利用可能です。
外から呼び出そうとした場合はエラーになります(しかしIEでは漏れてる…
var foo = function bar() {
    bar(); // Works
}
bar(); // ReferenceError

Order of parsing

varステートメントは関数宣言よりも前にパースされるため、下のような場合は一つ前にオーバーライドされる。
function foo() {}
var foo;

foo; // [function foo]
var foo = 2;
foo; // 2

How this works

JavaScriptでのthisは他の言語とは違うコンセプトを持っています。
そこで5つの違いをあげてる。//コメントはthisが示しているオブジェクト
this;// global object
foo();// global object - strict modeではundefinedに置き換わる
test.foo(); // test
new foo();// その場で作られたObject
// applyやcallではthisを指定できる
function foo(a, b, c) {}
var bar = {};
foo.apply(bar, [1, 2, 3]); // array will expand to the below
foo.call(bar, 1, 2, 3); // results in a = 1, b = 2, c = 3

Common pitfalls

さきほども言ったようにJavaScriptではthisの意味が他の言語と異なるため、実装方法にも気をつける必要がある。
Foo.method = function() {
    function test() {
        // this は global object を示す
    }
    test();// thisはFooであることを期待する
}
このようによく間違った書き方をしてしまう事があります。なので次のようにthatにthisを入れて、クロージャーにすることでこれを解決できます。
Foo.method = function() {
    var that = this;
    function test() {
        // that を this の代わりに使う
    }
    test();
}

Assigning methods

以下のように変数に代入してしまうと、thisがsomeObjectを示すということはなくなってしまいます。
var test = someObject.methodTest;
test();// thisはglobal object

Closures and references

JavaScriptの強力な機能の一つであるクロージャーについて
function Counter(start) {
    var count = start;
    return {
        increment: function() {
            count++;
        },

        get: function() {
            return count;
        }
    }
}

var foo = Counter(4);
foo.increment();
foo.get(); // 5
上記のgetやincrementはCounterスコープへの参照を持っていて、count変数にいつでもアクセスできる。

Why private variables work

count変数には外からアクセスできません。
function Counter(start) {
    var count = start;
    return {
        increment: function() {
            count++;
        },

        get: function() {
            return count;
        }
    }
}

var foo = Counter(4);
foo.increment();
foo.get(); // 5
var foo = new Counter(4);
foo.hack = function() {
    count = 1337;// グローバルのcountに書き込んでいる
};
foo.hack();
foo.get(); // 5
上記のコードでもcountは変更できません。それはfoo.hackがCounterのスコープに定義されたわけではないからです。

Closures inside loops

よくあるループでのミス
これを目的通りの振る舞いにするためにはiのコピーを持つ必要があります。
for(var i = 0; i < 10; i++) {
    setTimeout(function() {
        console.log(i);  // 10がぞろぞろ
    }, 1000);
}

Avoiding the reference problem

先ほどの失敗を踏まえて、iのコピーをそれぞれ持たせてみる。
これを簡単に行う方法として無名関数で囲む方法があります。
for(var i = 0; i < 10; i++) {
    (function(e) {
        setTimeout(function() {
            console.log(e);  
        }, 1000);
    })(i);
}
無名関数が呼ばれたときにiの値はパラーメータeとしてコピーされて受け取れます。
似たような書き方として以下のようにも書く事が可能です
for(var i = 0; i < 10; i++) {
    setTimeout((function(e) {
        return function() {
            console.log(e);
        }
    })(i), 1000)
}

The arguments object

すべての関数スコープには特別な値としてargumentsがあります。
argumentsは引数がありlengthプロパティもあるため配列のように見えるが、じっさいにはArray.prototypeから継承しているわけではなくオブジェクトです。
そのためpush, pop, sliceのような配列のメソッドを使うことはそのままではできません。

Converting to an array

arguments(Array likeオブジェクト)をArrayオブジェクトにする例。
しかしこの変換はとても遅いので性能を気にする場面では避けるべきかもしれません。
Array.prototype.slice.call(arguments);
パフォーマンス比較(concatは無視)

Modification "magic"

argumentsオブジェクトは書き換えができてしまうため下のような事が行える。
ただし、strict modeではこういう事はできなくなった。
function foo(a, b, c) {
    arguments[0] = 2;
    a; // 2

    b = 4;
    arguments[1]; // 4

    var d = c;
    d = 9;
    c; // 3
}
foo(1, 2, 3);

Performance myths and truths

arguments.calleeはパフォーマンスがよろしくないため、できるだけ関数名などを使うようにするべき。
またarguments.calleeはコンテキスト依存となるため、カプセル化を壊してしまう。

Scopes and namespaces

JavaScriptでは{...}でスコープができるわけではなく、あくまで関数スコープである。
function test() { // a scope
    for(var i = 0; i < 10; i++) { // スコープじゃない
        // count
    }
    console.log(i); // 10 
}
JavaScriptでもはっきりと区別できるものがあります。それはグローバルスコープです。
すべてが一つのグローバル名前空間を共有しているからです。

The bane of global variables

script A,Bはそれぞれ意味が異なる。
// script A
foo = '42';// グローバルスコープにfooを定義
// それぞれ違う
// script B
var foo = '42';// ローカルスコープにfooを定義
またglobalのfooをlocalで上書きすることができてしまう。
これは短いコードならまだわかるが、コード量が増えるとどこで上書きされているかの発見は困難となるためバグの原因になりやすい。
// global scope
var foo = 42;
function test() {
    // local scope
    foo = 21;// varを使ってない
}
test();
foo; // 21
そのため、外側のスコープに対して影響を与える事を考えている場合以外はvarステートメントを省略することは控えるべきである。

Name resolution order

グローバルも含めて、thisキーワードは"現在のオブジェクト"を参照している。
関数スコープはargumentsが定義されており、それは関数に渡された引数を含んでいる。
たとえば関数スコープの内側でfooという変数にアクセスしたときJavaScriptではどのようにルックアップしていくかを見ていきましょう。
  1. var fooステートメントが現在のスコープにあるならそれを使う
  2. 関数のパラーメータにfooがあるならそれを使う
  3. 関数自体がfooという名前ならそれを使う
  4. 外のスコープに行き、1から繰り返す

Namespaces

グローバル名前空間で変数定義などを行うと、名前の衝突などが起こることもあるため、その問題を回避するために無名関数で囲うという方法があります。
(function() {
    // a self contained "namespace"
    window.foo = function() {
        // an exposed closure
    };
})(); // execute the function immediately
この無名関数の即時実行は無名関数を()で囲い式にすることで実行することができています。
( // evaluate the function inside the paranthesis
function() {}
) // and return the function object
() // call the result of the evaluation
これは先頭がfunctionキーワードだと関数宣言と見なされてしまうための回避方法としてよく使われていて、他にも下のような書き方ができます。(上のやり方が好ましい気もするけど)
+function(){}();
(function(){}());
コードをカプセル化するのに無名関数で囲うことは有効なのでモジュール化をするために使うべき。

Constructors

newキーワードがついてるものはコンストラクタとして関数呼び出しされます。
コンストラクタ内でのthisは新しく作ったnew Objectを示します。
new Objectのprototypeはコンストラクタ関数のprototypeが設定されます。
コンストラクタ関数のreturnでオブジェクトが返されているとき以外はthis(new Object)が返されます。
function Foo() {
    this.bla = 1;
}
Foo.prototype.test = function() {
    console.log(this.bla);
};
var test = new Foo();// new忘れない
newキーワードをつけないでFooを読んだ場合はthisがグローバルオブジェクトを示してしまい悲惨な事になる。

Factories

newキーワードを外しても呼べるようにするためには明示的に値を返す必要がある。
function Bar() {
    var value = 1;
    return {// オブジェクトを返すのでthis(new Object)は返されない
        method: function() {
            return value;
        }
    }
}
Bar.prototype = {// これが無意味になってる
    foo: function() {}
};
new Bar();
Bar();
この方法ならnewをつけてもつけなくても同じ値が返ってくるが、new Bar()とした場合でもprototypeに影響を与えない。(つまりprototype継承が行われない)
そのためthis(new Object)にprototype拡張しても、実際にthis(new Object)を返すことがないためBar.prototypeは意味のない記述になってしまいます。

Creating new objects via factories

factoryの典型的な例
function Foo() {
    var obj = {};
    obj.value = 'blub';

    var private = 2;
    obj.someMethod = function(value) {
        this.value = value;
    }

    obj.getPrivate = function() {
        return private;
    }
    return obj;
}
内部でオブジェクトを作って返すfactoryパターンはメリットもありますが、デメリットも存在します。
  • 作ったオブジェクトでメソッドなどを共有しないのでメモリをより多く使う
  • factoryとから継承するためにはメソッドなどすべてコピーする必要がある
  • prototypeチェーンを捨てているため、言語の精神に反する面もある
newを付け忘れても問題なくなるけど、prototypeの恩賜を授かれない。
factoryを使ってnewを省略できるようにすることでバグは少なくなるかもしれないが、必ずしもそれはprototypeを捨てる事に直結はしない。最終的にはアプリケーションのニーズに合わせたスタイルをとり、そのスタイルにこだわる事が重要。

Equality and comparisons

JavaScriptには==と===の二つの比較演算子がある。
== は型変換を行って比較するため、見た目とは違った結果になることもある。
また型変換をするためパフォーマンスへの影響もある。
""           ==   "0"           // false
0            ==   ""            // true
0            ==   "0"           // true
false        ==   "false"       // false
false        ==   "0"           // true
false        ==   undefined     // false
false        ==   null          // false
null         ==   undefined     // true
" \t\r\n"    ==   0             // true

The strict equals operator

厳密比較演算子===を使うと、型変換による微妙なバグは避けられるでしょう。
また型変換を行わないのでパフォーマンス的にもこちら方が早い
""           ===   "0"           // false
0            ===   ""            // false
0            ===   "0"           // false
false        ===   "false"       // false
false        ===   "0"           // false
false        ===   undefined     // false
false        ===   null          // false
null         ===   undefined     // false
" \t\r\n"    ===   0             // false

Comparing objects

オブジェクト同士の比較
オブジェクトの比較では値が等しいかではなく、identityを比較しています。
つまり同じオブジェクトのインスタンスであるかを比較している。
{} === {};                   // false
new String('foo') === 'foo'; // false
new Number(10) === 10;       // false
var foo = {};
foo === foo;                 // true
厳密な比較演算子の使用を強く推奨する
(個人的には緩い比較の利用法もあるんじゃないかなーと思う

Arrays

Iteration

forで配列をなめる時はlengthをキャッシュしておけばより高速に動作する。
var list = [1, 2, 3, 4, 5, ...... 100000000];
// lengthが毎回参照されるのがいやなのでキャッシュする
for(var i = 0, l = list.length; i < l; i++) {
    console.log(list[i]);
}

The length property

lengthに数値を代入することで配列の切り捨てを行える。
var foo = [1, 2, 3, 4, 5, 6];
foo.length = 3;
foo; // [1, 2, 3]

foo.length = 6;
foo; // [1, 2, 3]

The Array constructor

配列はArrayコンストラクタを使っても作れますが、ほとんどの場合を除いてこれを使う必要はないため、リテラルを使って配列を作成する。
[1, 2, 3]; // Result: [1, 2, 3]
new Array(1, 2, 3); // Result: [1, 2, 3]

[3]; // Result: [3]
new Array(3); // Result: [undefined, undefined, undefined] 
new Array('3') // Result: ['3']
一つ使える方法があるならば、文字列の繰り返しを生成する場合には便利です。
new Array(count + 1).join(stringToRepeat);

The for in loop

オブジェクトを列挙するためにはfor inループを使用します。
ただしそのままではオブジェクト汚染の影響を受けてしまうので、hasOwnPropertyを使ってオブジェクト汚染を避ける方法があります。
// Poisoning Object.prototype
Object.prototype.bar = 1;
var foo = {moo: 2};
for(var i in foo) {
    console.log(i); // prints both bar and moo
}
// hasOwnPropertyを使ってオブジェクト汚染を避ける
for(var i in foo) {
    if (foo.hasOwnProperty(i)) {
        console.log(i);
    }
}
// こういう方法も
// Object.prototype.hasOwnPropertyを使う
var hasOwn = Object.prototype.hasOwnProperty;
for(var i in foo) {
    if (hasOwn.call(foo, i)) {
        console.log(i);
    }
}

The typeof operator

typeof(instanceof共々)はJavaScriptの最大の欠陥ともいえる。(完全にぶっ壊れてるぜ)
instanceofはまだ限られた使い道があるが、typeofは一つのuse caseしかない。

The JavaScript type table

typeofの比較表
Value               Class      Type
-------------------------------------
"foo"               String     string
new String("foo")   String     object
1.2                 Number     number
new Number(1.2)     Number     object
true                Boolean    boolean
new Boolean(true)   Boolean    object
new Date()          Date       object
new Error()         Error      object
[1,2,3]             Array      object
new Array(1, 2, 3)  Array      object
new Function("")    Function   function
/abc/g              RegExp     object (function in Nitro/V8)
new RegExp("meow")  RegExp     object (function in Nitro/V8)
{}                  Object     object
new Object()        Object     object
一貫性が存在していない…
Classはオブジェクトの[[Class]]プロパティ値を示している。この[[Class]]の値をとる方法はObject.prototype.toStringを使う事があげられる。

The Class of an object

Object.prototype.toStringを使って[[Class]]プロパティ値を使った判定方法の例
function is(type, obj) {
    var clas = Object.prototype.toString.call(obj).slice(8, -1);
    return obj !== undefined && obj !== null && clas === type;
}

is('String', 'test'); // true
is('String', new String('test')); // true

Testing for undefined variables

typeof foo !== 'undefined';
fooが本当に定義されているかを判定する方法。これが唯一のtypeofが役立つ利用法。

The instanceof operator

instanceof演算子は2つのオペランドのコンストラクタを比較します。
カスタムメイドオブジェクトの比較のみに使えて、native typeにはtypeofと同様に使いにくいものです。

Comparing custom objects

function Foo() {}
function Bar() {}
Bar.prototype = Foo;

new Bar() instanceof Bar; // true
new Bar() instanceof Foo; // false

Using instanceof with native types

予想とは異なる感じになる点がtypeofに似ている。
new String('foo') instanceof String; // true
new String('foo') instanceof Object; // true !

'foo' instanceof String; // false
'foo' instanceof Object; // false
そのためinstanceofはカスタムメイドオブジェクトについてのみ扱い、そのほかの場合はtypeofと同様に使うのを避けるべきです。

Type casting

Madness with new and built in types

ネイティブコンストラクタにnewをつけるかどうかで振る舞いは変わります。
new Number(10) === 10;     // False, Object and Number
Number(10) === 10;         // True, Number and Number
new Number(10) + 0 === 10; // True, 暗黙の変換をさせる
キャストで使える3つの方法
//Casting to a string
'' + 10 === '10'; // true
// Casting to a number
+'10' === 10; // true
// Casting to a boolean
!!'foo';   // true
!!'';      // false
!!'0';     // false
!!'1';     // true
!!'-1'     // true
!!{};      // true
!!true;    // true

undefined and null

他とは明らかに異なった値

The value undefined

undefinedはグローバル変数にundefinedの値が定義されているため、上書きすることが可能になってしまってる。
undefinedを返すケースは以下のような時
  • グローバル変数のundefinedにアクセスしたとき
  • 関数にreturn文がないときの返値
  • return文で何も返さないことを明示的にしている場合return;
  • ルックアップしてプロパティが存在しなかったとき
  • 関数のパラメーターに何も渡されなかったときの仮引数
  • 値がundefinedに設定されているもの

The case of the "overridden" undefined

undefinedがオーバーライドされているときには無名関数を利用してローカルで使えるようにするなどのテクニックがある(jQueryとかもやってた)
var undefined = 123;
(function(something, foo, undefined) {
    // undefinedが取得し直せる
    // undefined in the local scope does 
    // now again refer to the value

})('Hello World', 42);

Uses of null

nullの用途。
JavaScriptでは未定義な状態をundefinedで表したりしますが、本当のnullはデータの型がちがうだけのundefinedと同じもの。
つまり、Foo.prototype = null;のように書いたりする部分はundefinedに置き換えることが可能。

The evil eval

99.9%はevalを使うことなく実現できるはずなので使うのはできるだけ避けましょう。

eval in disguise

setTimeout と setInterval文字列を渡すとevalのように実行する。(グローバルスコープで実行される)

Security issues

出所が信用できない文字列を元にevalするのは絶対に避けるべき事。

setTimeout and setInterval

setTimeout と setIntervalはECMAではなくDOMの一部として実装されている。
どちらも第一引数で渡したパラーメータをグローバルオブジェクトによって呼び出すため、thisはグローバルオブジェクトを示します。
function Foo() {
    this.value = 42;
    this.method = function() {
        // thisはグローバルオブジェクトを参照してしまう
        console.log(this.value); // will log undefined
    };
    setTimeout(this.method, 500);
}
new Foo();

Stacking calls with setInterval

setIntervalは名前の通りxミリ秒ごとに呼び出しますが、あまり推奨できないものです。
下ようなコードは100ミリ秒ごとにfooを実行して欲しいですが、実際にはdropを起こしてずれることが多いです
function foo(){
    // something that blocks for 1 second
}
setInterval(foo, 100);
ただアニメーションなどで一定時間内で処理が終わるようにした場合はsetIntervalを使った方が安定するそうです。

Dealing with possible blocking code

解決方法としてはsetTimeoutを使って再帰的に呼び出すことがあげられる。
function foo(){
    // something that blocks for 1 second
    setTimeout(foo, 100);
}
foo();

Manually clearing timeouts

タイマーを消すにはclear*メソッドを使う
var id = setTimeout(foo, 1000);
clearTimeout(id);
タイマーIDがわからなければ力尽くでやる方法もあるが、普通にIDを追いかけるようにしましょう。
// clear "all" timeouts
for(var i = 1; i < 1000; i++) {
    clearTimeout(i);
}

Hidden eval magic

setTimeoutで呼び出す関数に引数を渡すには無名関数を使いましょう。
function foo(a, b, c) {}

// つかっちゃだめ
setTimeout('foo(1,2, 3)', 1000)

// 代わりに無名関数を使う
setTimeout(function() {
    foo(a, b, c);
}, 1000)

Automatic semicolon insertion

JavaScriptでは自動的にセミコロンを挿入する機能がある。
そのため変なところに改行があるだけで意図しない動作になったりする。
return // ここでreturn
{//ここら辺は死んでるコードになってしまう
    foo: 1
}
もう一つの例
var foo = function() {
} // missing semicolon after assignment
(function() {
    // do something in it's own scope
})();
// 上と下でまるで意味が変わる。
var foo = function(){
}( // セミコロンは入らないで、無名関数が引数として渡される。
    function() {
    }
)() // now call the result of the previous call
これらのようにセミコロンを明示的に入れないと意図しない動作になることがあるため、できるだけセミコロンを入れましょう。またif / elseのように{}を省略できるものもありますが、それも同様に省略しないようにするべきです。

1: uupaa 2011年02月13日(日) 午前5時48分

(ε・◇・)з ややっ!
argumentsをArray likeオブジェクトにする例。

argumentsをArrayオブジェクトにする例。
かも(ちがってたらごめんなさい)

2: azu 2011年02月13日(日) 午後1時13分

修正ed
なんでArray likeにしてたんだろ…


名前:  非公開コメント   

  • TB-URL  http://efcl.info/adiary/095/tb/