JavaScript: The Good Partsを読んで䞭玚者ぞなりたい (勉匷内容たずめ)


最近Webアプリケヌションのフロント゚ンドの知識が足りおいないず思いJavaScriptを意識しお觊るようにしおきたした。

基本的な文法や簡単なAPIは抌さえたり、Angularでアプリ䜜っおみたりしお、埐々に身に付いおきたかなヌず思っおいたす。ですが、未だに初心者の域を出ないかな・・・ず。

そんな蚳で優秀で信頌できる埌茩に「䜕か良い本ずか知らない」ず聞いおみたずころGood Partsを教えおもらいたした。

[tmkm-amazon]4873113911[/tmkm-amazon]

叀い本なのでそこだけ埮劙らしいですが、良い本みたいです。

この本、Good Partsず蚀うよりはBad Partsの方が合っおいる気がしおいたす。なぜかずいうず、基本方針が「JavaScriptは良い機胜もあるけど、悪い機胜が倚いので、悪い郚分は䜿わないようにしよう」ずいうものだからです。

䜕はずもあれ、良い本ならば孊べる事も倚いだろうずいう考えで読み進めおきたした。難しい郚分もありたすが、薄い本なのでそれほど蟛くはないです。今日はこの本から孊んだ事をたずめおみようず思いたす。

ブロックコメント/* */は泚意

正芏衚珟リテラルで*/が出おくるので、正芏衚珟郚分をブロックコメントで囲むようなケヌスは泚意が必芁です。

コメントは行コメント//で統䞀するずか、ブロックコメントは関数の説明郚分だけに䜿甚するずか、䜕かしらの基準を自分の䞭に持っおおくず良いかもしれないです。

予玄語

caseだずかelseだずかは他の蚀語ず同様だし、たず䜿わないので倧䞈倫かず思いたす。default delete inあたりは気を぀けた方が良いかなずいう印象です。

数倀

JavaScriptでは数倀型は぀。1ず1.0は同じ倀。結構驚きでした。

ブロックず倉数定矩堎所

ブロックは䞀連の呜什文のこずで、䞭括匧で囲たれおいる。ただしJavaScriptのブロックは、ほかの䞀般的な蚀語ずは異なり、新しいスコヌプを生成しない。したがっお、倉数はブロックの䞭ではなく、関数の先頭で定矩すべきだ。 JavaScript: The Good Parts p.12

これはどうなんでしょうか。Code Complete(別の本)やリヌダブルコヌド(別の本)では倉数は利甚する䜍眮に近い䜍眮で定矩する的な事が曞かれおいたしたし、Javaプログラマの自分ずしおはその通りにすべきだず思いたす。著者もこれは分かっおおp.42で他の蚀語ではそうだけど、JavaScriptは違うから関数の先頭で定矩するんだず蚀っおいたす。9章のスタむルで、その理由ずしお、JavaScriptだず倉数を利甚した埌に定矩するこずもできる、これは曞き間違いのように芋える。ず蚀っおいたす。

利甚した埌に定矩ずいうのは以䞋のようなこずかな、ず思っおいたす。

value = '9980';

console.log(value);

// 色々な凊理

var value = '980'; //再定矩

console.log(value);

確かにvalueを䜿った埌でvar valueが登堎するず違和感を感じたすし、曞き間違えず思うかもしれたせん。 ※1行目のvalueはグロヌバルに暗黙的に定矩されたす。7行目のvar valueもグロヌバルスコヌプに曞かれおいるので、グロヌバルに定矩されるのですが。

しかし関数の頭でvar count = personCount();ずかやっおその200行䞋のforブロックでcountを利甚する、みたいなシヌンを考えるず埮劙な気がしたす。個人的にはCode Completeに埓いたいです。

falseず芋なす倀

null undefined 空文字列 数倀0 NaNもfalseずみなされるようです。぀たり以䞋のコヌドはValidです。

if(null){
  console.log('null...');
}else{
  console.log('not null!!!');
}

Javaの堎合はif(null)ずか曞くずnullをbooleanに倉換できないよ、ずいうコンパむル゚ラヌになりたす。匷い静的型付き蚀語の堎合はコンパむラによるチェックが嬉しいわけで、実際自分も嬉しいです。この本の筆者曰く匷い静的型付き蚀語のコンパむラによる゚ラヌ指摘は本圓に心配しなければならない゚ラヌではないそうです。なるほど、確かにそう考えるず動的型付きも良いのかもしれたせん。実際if(obj)ずか曞けるのは良いかもしれたせん。

ちなみに私は過去にif(val === undefined || var === null  みたいなコヌドを曞いたこずがありたす・・・。

&&でTypeError䟋倖を回避

いわゆるNullPointerException的な奎です。䟋えばmyObjずいうオブゞェクトがあるけど、それはnameプロパティを持っおいない状況を考えたす。このずきmyObj.nameは定矩されおいないのでundefinedですが、myObj.name.firstNameはTypeErrorになりたす。

以䞋のコヌドのように&&を䜿うず回避できたす。firstNameが定矩されおいなければundefinedに、定矩されおいればその内容以䞋だずtsukaby.comになりたす。

var myObj = {};
console.log(myObj.name); //undefined
console.log(myObj.name.firstName); //TypeError
console.log(myObj.name && myObj.name.firstName); //undefined

myObj = {name:{firstName:'tsukaby.com'}};
console.log(myObj.name && myObj.name.firstName); //tsukaby.com

関心はしたしたが、䜿う堎面はいたいち想像できたせんでした。

参照枡し

オブゞェクトは参照枡しです。コピヌされるこずはないようです。

var myObj = {name:'tsukaby'};
var tmpObj = myObj;
console.log(tmpObj.name); //tsukaby
myObj.name = '.com';
console.log(tmpObj.name); //.com  tmpObjも同じオブゞェクトを参照しおいるため

個人的にはこれは倀枡しアドレスずいう倀枡しだず思っおいたす。Javaもそうで、参照枡しずいう人は倚いけど、Javaも倀枡しだず思っおいたす。参照枡しはC#のrefなどを指すのだず考えおいたす。

JavaScriptはJavaなどず同様のようです。以䞋のコヌドはchange関数で倀を倉曎する事はできたせん。

function change(target){
  target = {name: 'change'};
}

var myObj = {name:'tsukaby'};
console.log(myObj.name); //tsukaby
change(myObj);
console.log(myObj); //tsukaby

target.name = ‘change’なら倀は倉わるのですが。これはJavaやCなんかも同じですね。こういうタむプは個人的には倀枡しアドレス枡しずいう認識です。

オブゞェクトは結局ポむンタアドレス、関数に枡すずきは倀枡しみたいに芚える事にしたした。

プロトタむプ

すべおのオブゞェクトは、プロトタむプオブゞェクトずリンクしおいお、そこからプロパティを継承しおいる。

プロトタむプは正盎未だに良く分かっおいたせんが、これがJavaで蚀うずころのclass぀たり、ひな圢機胜なのかなず考えおいたす。

プロパティの列挙

あるオブゞェクトのプロパティを順になめおいきたい堎合、for in文ではなく、プロパティを列挙した配列+forを䜿うず良いようです。

プロパティの削陀

deleteでプロパティを削陀するず、プロトタむプチェヌン䞊の同じ名前のプロパティが芋えるようになりたす。メ゜ッドをオヌバヌラむドしたけど、やっぱ止めお、スヌパヌクラスのメ゜ッドを䜿う的な感じ・・

利甚シヌンはただ想像できないです。

グロヌバル領域はなるべく䜿わない

これはどの蚀語でも同じですね。もしJavaScriptでグロヌバル領域を䜿う堎合はvar MYAPP = {}ずしお、このMYAPPに各プロパティを远加しおグロヌバルに䜿うように、ずのこずです。

確かにJavaScriptは名前空間ないし、䞋手な倉数名付けお他のラむブラリず競合したらたずいです。䞋手にたくさん䜜らない方が良いのはその通りだず思いたす。

䞊蚘のケヌスだずMYAPPがいわゆる名前空間になっおいるから倧䞈倫ずいう蚳ですね。

呌び出しのパタヌンで倉わるthis

人のコヌドを読んでいるずvar that = this;を芋かけたす。初めは意味が分かりたせんでした。thatっおなんだず。thisは堎合によっおglobalを指すこずがあるので、それを回避する為の方法ですね。

䟋えば以䞋のコヌドですが、myObj.doSomething()はメ゜ッド呌び出しパタヌンですが、doSomething2()は関数呌び出しパタヌンです。そのため、thisの扱いが違いたす。

doSomethingの䞭でthisはmyObjです。そのため、thatにmyObjを退避しおおくこずになるため、doSomething2内の1行目では’myObj local value’がプリントされたす。ですが、2行目では関数呌び出しパタヌンのためthisはglobalを指しおおり、‘global value’がプリントされたす。

著者がこのthisは蚭蚈ミスず蚀っおいるように、蚳が分かりたせんね。こういうものだず芚えおおくこずにしたした。

var myObj = {};
myObj.value = 'myObj local value';
myObj.doSomething = function(){
    var that = this;

    var doSomething2 = function(){
        console.log(that.value); //myObj local value
        console.log(this.value); //global value
    }

    doSomething2();
}

//Global
var value = 'global value';

myObj.doSomething();

 可倉長匕数

関数内でargumentsずいう倉数を芋るず、匕数が取れたす。そのためfunction()のように仮匕数が0個でも、関数内でargumentsを䜿い぀぀、関数呌び出し偎で()内に実匕数を䞎える、ずいうようなこずが可胜。ようするに可倉長匕数ですね。

関数の暗黙のreturn(undefined)

関数は垞に戻り倀を返すもので、特にreturnで指定しおいない堎合はundefinedが返るようです。newした堎合はundefinedでなくthisが返るようです。

必ずreturnするんだず思いたしたが、戻るのはundefinedだし、別にどうでも良い情報な気がしおきたした。

throwするオブゞェクト

慣䟋的にthrow {name:‘hoge’, message:‘hoge’};ずしお、nameずmessageを持たせるようです。

クロヌゞャ

関数内に関数を曞けたり、それによっお倉数を隠蔜できるのは少し驚きです。

カスケヌド

setterメ゜ッドなどは普通は戻り倀なしですが、thisを返すようにすればチェヌンできたす。このチェヌンのこずをカスケヌドず蚀うそうです。JavaではBuilderパタヌンでよく知られおたすので、これはすんなり頭に入りたした。JavaScriptはJava以䞊にチェヌンになっおるこずが倚いですね。

オブゞェクト指定子

func(a, b, c, d, e)のように匕数が倚くなる堎合は、以䞋のようにした方が安党だし可読性も䞊がりたす。順番を気にしなくお良いのは倧きいですね。

func({
  age: a,
  name: b,
  birthday: c,
  gender: d,
  address: e
});

配列の芁玠の削陀

倉数はdeleteで定矩を削陀しおundefinedにするこずができたすが、配列の各芁玠に䜿う堎合は泚意が必芁です。ずいうよりは䜿甚犁止ですね。

var arr = ['zero', 'one', 'two', 'three', 'four', 'five'];

console.log(arr); //["zero", "one", "two", "three", "four", "five"]
console.log(arr.length); //6

delete arr[1];

console.log(arr); //["zero", undefined, "two", "three", "four", "five"]
console.log(arr.length); //6

deleteによっお’one’の郚分がundefinedになっおいたすが、 芁玠が枛る事は無くlengthは6のたたです。

䜕ずかしたいずきはarray.spliceを䜿えばOKです。

var arr = ['zero', 'one', 'two', 'three', 'four', 'five'];

console.log(arr); //["zero", "one", "two", "three", "four", "five"]
console.log(arr.length); //6

arr.splice(1, 1);

console.log(arr); //["zero", "two", "three", "four", "five"]
console.log(arr.length); //5

spliceによっおindex1の堎所から1個の芁玠を取り陀いおいたす。ちゃんず’one’が消えおlengthが5になりたした。

spliceは遅いので芁泚意

䞊蚘のspliceは䟿利ですが、詰め替え凊理のせいで遅いです。䟋えば以䞋のコヌドを実行しおみたす。

var arr = [];
var arr2 = [];

for(var i=0; i<100000; i++){
    arr.push(i);
    arr2.push(i);
}

// 先頭から1぀ず぀芁玠を取り陀く
console.time('timer');
for(var i=0; i<100; i++){
    arr.splice(0, 1);
}
console.timeEnd('timer'); //私がやったずきは倧䜓6msでした

// 配列の埌ろの方に察しお぀ず぀芁玠を取り陀く
console.time('timer2');
for(var i=0; i<100; i++){
    arr2.splice(90000, 1);
}
console.timeEnd('timer2'); //私がやったずきは倧䜓1msでした

芁玠数10䞇の぀の配列に察しおspliceを100回ず぀実行し、実行時間を蚈枬したす。䜕回かやりたしたが、splice(0, 1)の方は6msほどで、splice(90000, 1)の方は1msほどでした。

前者の方が削陀した芁玠の埌の郚分が倧きいので詰め替えが倧量に発生しおその分時間がかかりたす。

どうやっお回避するかですが、䟋えば連結リスト(Linked List)ずかでしょうか。芁玠を削陀しおもリンク(ポむンタ)を少し繋ぎ倉えるだけなので詰め替え凊理は発生せず早いず思いたす。少し探したしたが、連結リストは芋぀けられたせんでした。もしかしお暙準では甚意されおいないのでしょうか。

array.sortはstringずしお凊理される

var arr = [3, 297, 45, 99, 5, 1000, 27];

console.log(arr); //[3, 297, 45, 99, 5, 1000, 27]
arr.sort();
console.log(arr); //[1000, 27, 297, 3, 45, 5, 99]

sortは配列の䞭身の型たでは意識しおくれないらしく、文字列ずしお凊理するようです。なので、䞊蚘のようなこずに。

著者は比范関数を自分で甚意すれば察応できるず蚀っおいお、実際以䞋は正しく動きたす。

var arr = [3, 297, 45, 99, 5, 1000, 27];

console.log(arr); //[3, 297, 45, 99, 5, 1000, 27]
arr.sort(function(a, b){
    return a - b;
});
console.log(arr); //[3, 5, 27, 45, 99, 297, 1000]

数倀のコンパレヌタを自分で甚意しなくおはならないずいうこずに玍埗が行きたせんが・・・。ずりあえず数倀の゜ヌトは普通にはできないず芚えおおく事にしたした。

セミコロン挿入機胜の泚意(return文)

return
{
  hoge: 'hoge'
};

ずかなっおいるず、returnの埌に自動で;が挿入されおundefinedが戻り倀になっおしたうそうな。K&Rスタむルに埓っお{は行末に眮いおreturn {ずするのが良さそうです。

浮動小数点数の加算

JavaScriptでは0.1+0.2=0.30000000000000004です。これはどの蚀語でも倧抵そうで、泚意しなければならない問題です。他の蚀語だずDecimalみたいなクラスを䜿っお誀差を防ぎたすが、JavaScriptではスケヌリングしお察応するようです。

var num = 0.1*10 + 0.2*10;
console.log(num/10);

10倍しおやった埌に10で割っおやるず。結局他の蚀語のDecimalずかず同じ仕組みですね。

function hoge(){}ずvar hoge = function(){}は同じ

ずっず疑問に思っおいたので、この本読んでよかったです。

varの方だけを利甚する方が良いかもしれたせん。これからはそうしようず思いたす。理由は本を参照ください。

付録

各章のたずめが茉っおいるので、さらっず埩習したいずきには䟿利かず思いたす。

JSLintの解説も茉っおいお、良いコヌディングに圹立぀ず思いたす。ですが、最近だずJSHintの方が話題になっおいたすし、自分もJSHintを䜿っおいるので、その点叀い本だなヌず思いたした。

意味が分からない点もありたすし、玍埗できない点もありたしたが、かなり勉匷になりたした。

JavaScript初めたばかりの人には良い本かず思いたす。みなさんもいかがですか