項目10　withは避けよう

おはようございますｍｍ今日もやってるワンこです。

最近べジータ様のお料理教室にはまってて中毒症状が起きています。あぁー共感するな～っと思ってさすが王子様＞ω＜）

本題のEffectiveJavascriptについてですが、あいにく私語学力も技術力も足りず、簡単なものを軽くやると言い訳します。ごめんなさい＞ω＜）

# withのやること

```javascript:doNotNameYourJSFileLongerThanThisOne.js
function secretPassword(password){
    var thePowerfulAndAwesomePrinceInside = new Bejita();
    with(theAwesomeAndPowerfulPrinceInside){
        doCooking('Okonomiyaki');
        doSinging('I wont tell you my password~');
        alert(password); // Ooops, Bejita's password leaks!!
    }
}
```

ちなみに上のやつはOoops以前にTypoです＞ω＜）でうちの王子様のタイトル多いので、withブロックの中では変数やメソッドを使う際自動的にwithに渡したオブジェクトを参照して、いろいろと長いものを入力する手間を省けてくれる。

やってることは **ほぼ** 下のと同じです

```javascript:doNotNameYourJSFileLongerThanThisOne.js
function secretPassword(password){
    var thePowerfulAndAwesomePrinceInside = new Bejita();
    thePowerfulAndAwesomePrinceInside.doCooking('Okonomiyaki');
    thePowerfulAndAwesomePrinceInside.doSinging('I wont tell you my password~');
    alert(password); // Feel free to leak your own password
}
```

したのと比べてwithを使ったのがだいぶ綺麗ですが、バグってしまったらおしまいですね。

# なぜwithを使ってはいけないですか？

小難しいことばよくわかりませんが、たぶんこんな感じでしょうか？

>withを使うとローカルスコープが汚染される

普通はグローバルスコープへの汚染をしないようにグローバル変数の宣言を控えてますが、使い捨てのローカルスコープも同じってことですね。

withを一度使うと、オブジェクトが一時的にスコープチェーンの先頭にくる。例えてみればオブジェクトのメソッドと変数とプロトタイプの中身などオブジェクトから参照できるものすべてがいまのスコープに入ってくる。普通その内容量は遥かに必要を上回ってますし、一番厄介なのは、普通に参照したいほかのスコープチェーン上の変数とか（password）はオブジェクトのものに上書きされるかもしれません。ローカルにあったから遡ることはしなくなるからです。

危険性というと：

* オブジェクトに運悪く同名変数関数があると外の本当に参照したいものを参照できなくなる

* いま安全なオブジェクトでもいつ差分が入って落ちるかもしれません

* まだ思いついていない

オブジェクトを使う前にいちいち中身をチェックする人はそう多くないと思って、こういう今動いていてもいつ落ちるかわからず、オブジェクトと普通のスコープチェーンのどれを参照しているかわからない状態は汚いといわれても仕方がないですね。

ちなみにwithを使うとstrict modeだと怒られそうです。ES5ではwithより、短い名前の変数にアサインして使うようにと。

```javascript:doNotNameYourJSFileLongerThanThisOne.js
function secretPassword(password){
    var thePowerfulAndAwesomePrinceInside = new Bejita();
    var t = thePowerfulAndAwesomePrinceInside;
    t.doCooking('Okonomiyaki');
    t.doSinging('I wont tell you my password~');
    alert(password); // Feel free to leak your own password
}
```

省けた手間よりリスクが大きいってことです。Perlのデフォルトimportもそうですしね。めんどくさいかもしれませんが、システムが大きくなるほど、コードをうるさく書かないといけなくなるものですよ´・ω・`）

Mozillaのwith構文解釈です：
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements/with?redirectlocale=en-US&redirectslug=Core_JavaScript_1.5_Reference%2FStatements%2Fwith

# withは遅いですか？

>多少遅くなるかもしれませんが、使わない要因のメインには入れそうもない

サイ本とEffectiveJavascriptによると、遅くて当然だそうです。それもそうです。スコープチェーンの先頭に置くこと自体は重くないが（Mozillaによる）、ローカル変数を訪問するたびにオブジェクトのプロトタイプチェーンをサーチしてみろ！ってことです。
 
が実際にwithの効率は実装によりますし、SafariやOperaとかだとwith(Math)程度ならほぼスピードは同じの報告もどっかのブログあるらしく、一般的な使用だとそう遅くはないかも。

まぁあくまで一般的な使用です。怪しい使い方でバンバン使うとさすがに遅くなるでしょう。。。

# withのほかの副作用

>サイ本によると、withの中で変数や関数を宣言したら面白いことになると

きたきたーーーー試してきました！！！`・ω・´）９。

```javascript:doNotNameYourJSFileLongerThanThisOne.js
function Saiyan( name ){
    this.name   = name;
    this.cutNinjin = function(){
        alert('Cut Ninjin!!!');
    };
    return this;
}

var vegeta = new Saiyan('Vegeta');

with( vegeta ){
    var password = 'sukiyaki';

    alert( name );         // Vegeta
    alert( password );     // sukiyaki

    var name = 'Goku';
    function cutNinjin(){
        alert('Bakibaki Ninjin!!!');
    }
    function cutShoga(){
        alert('Bakibaki Shoga!!!');
    }

    alert( name );         // Goku
    cutNinjin();           // Cut Ninjin!!!
    cutShoga();            // Bakibaki Shoga!!!
}

alert( vegeta.name );      // Goku
alert( vegeta.password );  // undefined
vegeta.cutNinjin();        // Cut Ninjin!!!
//vegeta.cutShoga();       // Error
```

まとめるとこんな感じです：

* オブジェクトにあった変数名はvarでローカル宣言しようとしてもオブジェクト変数を上書きしちゃう
* オブジェクトにない変数名は普通に使える

* オブジェクトにあった関数名はfunctionで宣言しても使えない、オブジェクトの関数を呼び出すことになっちゃう
* 上書きにはならない

残念ながら今のところ天下のIEでしか試してないから信憑性が薄いといえる。。。もうちょっとがんばってみる。。。

# なぜwithに支持者がいっぱいいるのか？

Googleしてみてください、みんなwithを使いたがってます＞ω＜）

というのも読みにくいコードを書くの誇りだと思っているプログラマーの悲しい性分。使いにくくなるほど使いたくなるものです。ここでプログラミングと開発作業の違いが出てきましたね。

* プログラミングは遊び～

* 開発は仕事だからかな

うちはプログラマーちゃうし、気をつけてやっておこう～
それではご縁があればまた今度～