2009年4月14日火曜日

JavaScript: The Good Parts

今更だけど見てみた。


1時間以上あるのに軽く引くが、本当に重要なのは30分程度。残りはこの人の経験談や、JavaScript界隈の近況、質疑応答。
この人のプレゼンは、皮肉がきいていて面白い。とりあえず、わかった範囲でメモっておく。

JavaScriptの現状
  • いまだに最も誤解された言語
  • 誤用しては怒っている人多し
  • 最もすばらしいアイデアから、もっともひどいアイデアまで含まれている
  • こんなに幅の広い言語はほかにない
  • コンピュータ科学者からカット&ペースト厨まで、どの言語よりも幅広いスキルの人が使っている
JavaScriptへの不満
  • ブラウザプログラミングはひどいもんだ。 => まったくその通り
  • 十分な速度が出ない。 => 現在ではすでにJSではなくDOMの問題。今はランタイムは十分速い。
  • 失敗の積み重ねだ。 => Javaが完全に失敗した環境でうまくやりつづけているだろ?

影響を受けた言語
Self:
  • prototypal inheritance
  • dynamic objects
Java:
  • syntax
  • conventions
Scheme:
  • lambda
  • loose typing
Perl:
  • regular expressions
Schemeさんパネェッス。
loose typingを問題視する人もいるが、テストすればよい。テストは他の言語でも必要 型チェックだけじゃわからないことは多い。Javaのシンタックスはあんまよくないね。

Bad Parts
  • グローバル変数。
  • + をaddと結合に使う。Javaもやってるが、Javaは強い型つけを持ってるから問題ない。
  • セミコロン。初心者向けにCのシンタックスを導入したが、予期しないエラーがおきたりする。後述。
  • typeof。役に立たない。なんでもObjectになってしまう。
  • with と eval。evalは一番誤用されている。evalを使ってるときは、なんかまずいことをやってる。
  • まがいものの配列。本来はメモリを区切ってすばやくアクセスできるが、JSのはこういうのじゃない。実際はハッシュテーブル。
  • == と !=。Cから受け継いだ問題の多いシンタックス。
  • false, null, undefined, NaN。たくさんありすぎ。
どうなるかわかるだろうか?
'' == '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
常に ===を使うべき。==は(暗黙の型変換がカオスすぎるので)使ってはいけない。本当は間違いだけど、偶然うまくいくケースもある。
// 間違い
var obj = myObject[name]
if (obj == null) {
....

// 正解
var obj = myObject[name]
if (obj == undefined) {

単独では良い機能が、関連するとがうまく動かないケース
  • Objectは他のオブジェクトを継承できる
  • 関数はオブジェクトのメンバになれる
  • for..in文は、継承した関数とデータメンバを区別しない
=> 全然嬉しくない挙動

実際、for .. in は問題が多い
// 浅いとか深いとか、よくわかんなかった

Bad Heritage
ブロックのないステートメント:
if (foo)
bar();
expression statement:
  foo;
Floating point arithmetic:
  0.1 + 0.2 !== 0.3
// JSの問題というわけではないんだが
++ and --:
バッファオーバーランとか色々問題があるらしい。コードもトリッキーになる。

switch:
Javaと同じ問題。falling through

Good Parts
Lambda:
パワフルで安全

Dynamic Objects:
非常にパワフルで使いやすい

Loose Typing:
良い。クラスとかいらない。

Object Literals:
とてもよい。JSONとか。

Inheritance
コードの再利用。クラスベースとプロトタイプベースがある。
よく理解されていないが、プロトタイプベースはとてもパワフル。

Prototype Inheritance
Classは不要、オブジェクトから継承。
他のオブジェクトへのリンクを持ち、委譲する方法がある。
var newObject = Object.create(oldObject);

if (typeof Object.create !== 'function') {
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
new はクラスベースっぽい記法を提供しているが、あまりよろしくない。コンストラクタ関数を呼ぶときにはnewが必要だが、忘れるとグローバルオブジェクトが変更されてしまう。そして、その際にはまったく警告が出ない。私は危険だから使わない。

Global変数いくない
var names = ['one', 'two'....]

functionでスコープ制限したらどうだろう?
function hoge(n) {
var names = ['one', 'two'...]
return names[n]
}
=> 遅い。呼び出しごとに配列が初期化されてしまう。

クロージャを使おう!
var digit_name = function() {
var names = [...]

return function(n) {
return names[n]
};
}
=> 無名関数のスコープ内で一度だけ初期化される。遅くない。これは、コンストラクタパターンとして一般化できる。といいつつ、次のスライドがModule Patternなのはなぜだ。

Module Pattern
var singleton = function() {
// 無名functionのスコープにとじこめられる
var privateVariable;
function privateFunction(x) {
..privateVariable...
}
// Objectリテラルで無名関数のスコープを使うように定義
return {
firstMethod: function (a, b) {
...privateVariable...
},
secondMethod: function(c) {
...privateFunction()....
}
};
}();
これは、(ようやく)コンストラクタに応用できる。

Power Constructor
1. Make an object.
  • Object literal
  • new
  • Object.create
  • call another power constructor
2. Define some variables and functions
これがプライベートメンバになる
3. 特権メソッドでobjectを複製する
4. 作ったobjectをかえす

コードで見てみると...
function myPowerConstructor(x) {
var that = otherMaker(x);
var secret = f(x);
that.priv = function() {
.... secret x that ....
};
return that;
}

コーディングスタイル
return {

}

return
{

}
どちらがいいか?これは、感情的な宗教論争ではない。少なくともJSに関しては。
return
{
ok: false
}
このように書いた場合、何も返らない。これは、returnの後ろに暗黙的にセミコロンが挿入されるから。
return;
{
ok: false
}
JavaScriptにはブロックスコープない。
ok: false
はラベルだとみなされる。
return;
{
ok: false;
};
こうなるということ。どのみち、return以降は到達しない文。

ビューティフルコード
JSLint使いなさい。Bad Partsを避けるように強制してくれる。注意しておくが、これを最初に使うと凹むことは請け合い。

他の良い点
安定してるぜ!1999からデザインがかわってないのだ。

標準化動向とか質疑応答とか省略。あー…うん。1度Youtubeの動画を貼ってみたかっただけなんだ…。

5 件のコメント:

masakanou さんのコメント...

falling throughってJavaではまだ残ってんの?

C#だとコンパイル通らない気が。

kentaro さんのコメント...

残ってるよん。Javaができた頃から文句言われてたけど、この手の基本的な言語仕様は、互換性を重視するJavaでは変わる可能性はすごく低いと思う。Java5でもかわんなかったし。

masakanou さんのコメント...

そろそろ読み終わったかな

サイ本5版とどっちを先に読むべき?

kentaro714 さんのコメント...

両方読んだ感じだと、たぶんGood Parts先に読んだほうが効率が良いと思う。ただ、理解を深めたいなら、先にサイ本のスコープチェーン、クロージャ、オブジェクト(プロトタイプ)の部分だけ読んどいてもいいかも。

masakanou さんのコメント...

>理解を深めたいなら、先にサイ本のスコープチェーン、クロージャ、オブジェクト(プロトタイプ)の部分だけ読んどいてもいいかも。

参考になります。
とりあえず、部屋に「はじJS(オライリー)」と「まるJS」があったので、そのへんの部分から読んでみます。