AWS ToolkitでTokyo RegionのSimpleDBに接続

AWS ToolkitはまだTokyo Regionに対応してないけど、SimpleDBの接続先追加は↓でいけた

eclipse/plugins/com.amazonaws.eclipse.datatools.enablement.simpledb_1.0.0.v201101181646/properties/connection.properties

endpoints = US-East (Northern Virginia) sdb.amazonaws.com, \
                    US-West (Northern California) sdb.us-west-1.amazonaws.com, \
                    EU-West (Ireland) sdb.eu-west-1.amazonaws.com, \
                    Asia Pacific (Singapore) sdb.ap-southeast-1.amazonaws.com, \
                    Asia Pacific (Tokyo) sdb.ap-northeast-1.amazonaws.com

「JavaScript Patterns」読了

JavaScript Patterns: Build Better Applications with Coding and Design Patterns

JavaScript Patterns: Build Better Applications with Coding and Design Patterns

JavaScript Patterns(iTunes)
読みました。
JavaScriptのパターン(⊇デザパタ)まとめ本。
DOM(ブラウザ)関連は最後の1章のみ。
以下適当まとめ。

変数宣言

// antipattern
function foo() {
    // aはローカル、bはグローバル
    var a = b = 0;
    // ...
}
// antipattern
myname = "global";
function func() {
    console.log(myname); // "undefined"
    var myname = "local";
    console.log(myname); // "local"
}
func();

myname = "global";
function func() {
    var myname;
    console.log(myname); // "undefined"
    myname = "local";
    console.log(myname); // "local"
}
func();

のように振舞う。ローカル変数は関数スコープでhoisting(持ち上げる)されるので(not in ES Specification)、混乱を避けるためにすべての変数は先頭で宣言するのがベスト。

forループ

オーソドックスなforループ

for (var i = 0; i < myarray.length; i += 1) {
    // ...
}

はmyarrayがHTMLCollectionオブジェクト(document.getElementsByTagName()等)の場合、lengthプロパティにアクセスする度にDOMを走査するために高くつく(DOMは重いよ)。キャッシュしとこう。

for (var i = 0, max = myarray.length; i < max; i += 1) {
    // ...
}

ループのちょっとした最適化

// 変数を1個減らす
for (var i = arr.length; i--; ) {
     // ...
}

// lengthとの比較より0との比較の方が安くつく
var i = arr.length;
while (i--) {
    // ...
}

switch文

// switch文ではswitchとcaseのインデントレベルを同じにしよう
switch (inspect_me) {
case 0:
    // ...
    break;
case 1:
    // ...
    break;
default:
    // ...
}

eval

どーしてもeval使わなきゃダメかなってときはnew Functionも候補。
new Functionに渡されたコードはローカルの関数スコープで実行されるから。immediate functionでもおk。

eval("var a = 1; console.log(a);");
new Function("var b = 2; console.log(b);")();
(function() {
    eval("var c = 3; console.log(c);");
})();
console.log(typeof a); // number
console.log(typeof b); // undefined
console.log(typeof c); // undefined(Firefox), number(Chrome)?

ここら辺によるとWebkitのDevToolコンソールのバグ(htmlから試したらundefined)
javascript - How come eval doesn't have access to the scoped variables under a with statement? - Stack Overflow
Issue 51496 - chromium - An open-source project to help move the web forward. - Monorail
Global eval. What are the options? — Perfection Kills

数値

0で始まる文字列はES3だと8進数と解釈されるがES5で変更される。parseIntでは基数を明示して混乱を避けよう。

var month = "06";
    year = "09";
month = parseInt(month, 10);
year = parseInt(year, 10);

↓はパフォーマンスいいけど余計なのあるとダメ。

+"08" // 8
Number("08"); // 8
+"08 hoge" // NaN
Number("08 hoge"); // NaN
parseInt("08 hoge", 10); // 8

Arrayコンストラクタのうまい使い方

// 255文字のスペースが欲しい
var white = new Array(256).join(' ');

isArray

ES5ではArray.isArrayが定義されたよ。

Array.isArray([]); // true

// false
Array.isArray({
    length: 1,
    "0": 1,
    slice: function() {}
});
if (!Array.isArray) {
    Array.isArray = function (arr) {
         return Object.prototype.toString.call(arr) === "[object Array]";
    };
}

正規表現リテラル

ES3だと正規表現リテラルは1回しかオブジェクトを作らないけどES5だとその都度作るから気を付けて。

var r1 = /[a-z]/;
var r2 = /[a-z]/;
console.log(r1 === r2); // false

(コメント指摘追記)
上の例だとES3でもfalseでした。
パース時にオブジェクトが1回だけ作られるので正しくは↓です。

function getRE() {
    return /[a-z]/;
}
re1 = getRE();
re2 = getRE();
console.log(re1 === re2); // true(ES3), false(ES5)

Self-Defining Function

// 初期化が必要なヤツとかに便利
var scareMe = function() {
    console.log("Boo!");
    scareMe = function() {
        console.log("Double boo!");
    };
};
scareMe(); // Boo!
scareMe(); // Double boo!

Init-Time Branching

// 実行時にその都度判定するんじゃなくて、読み込み時にだけ行う
var utils = {
    addListener: null,
    removeListener: null
};

if (window.addEventListener) {
    utils.addListener = function(el, type, fn) { el.addEventListener(type, fun, false); };
    utils.removeListener = function(el, type, fun) { el.removeEventListener(type, fun, false); };
} else if (window.attachEvent) {
    utils.addListener = function(el, type, fn) { el.attachEvent('on' + type, fun); };
    utils.removeListener = function(el, type, fun) { el.detachEvent('on' + type, fun); };
} else {
    utils.addListener = function(el, type, fn) { el['on' + type] = fun; };
    utils.removeListener = function(el, type, fun) { el['on' + type]= fun; };
}

メモ化

// 関数のプロパティを利用するだけ
var myFunc = function(param) {
    if (!myFunc.cache[param]) {
        var result = {};
        // expensive operation
        myFunc.cache[param] = result;
    }
    return myFunc.cache[param];
};
myFunc.cache = {};

カリー化

// カリー化一般関数
function schonfinkelize(fn) {
    var slice = Array.prototype.slice,
        stored_args = slice.call(arguments, 1);
    return function() {
        // sliceしてるのは配列にしてconcatを使いたいからだよ
        var new_args = slice.call(arguments),
            args = stored_args.concat(new_args);
        return fn.apply(null, args);
    };
}

function add(a, b) {
    return a + b;
}
var newadd = schonfinkelize(add, 5);
newadd(4); // 9
schonfinkelize(add, 5)(10); // 15

名前空間

var MYAPP = MYAPP || {}

staticメソッド

var Gadget = function() {};
Gadget.isShiny = function() {
    return "you bet";
}

Chaining Pattern

returnする値が特にないときはreturn this;を検討してみ。

継承

// クラスライクな継承関数
function inherit(C, P) {
    var F = function() {};
    F.prototype = P.prototype;
    C.prototype = new F();
    // super(予約語)の代わり
    C.uber = P.prototype;
    C.prototype.constructor = C;
}

ES5ではprototypalな継承関数が定義されてる。

var child = Object.create(parent);

デザインパターン

// Singleton
function Universe() {
    var instance = this;
    this.start_time = 0;
    Universe = function() {
        return instance;
    };
}
var u1 = new Universe();
var u2 = new Universe();
u1 === u2; // true

// これだと最初のオブジェクト作成後にprototypeにプロパティ追加しても反映されかったりするんで
function Universe() {
    var instance;
    Universe = function() {
        return instance;
    };
    Universe.prototype = this;
    instance = new Universe();
    instance.constructor = Universe;
    this.start_time = 0;
    return instance;
}

DOM

DOMアクセスは高価なので

  • ループの中でDOMアクセスは避ける
  • DOMへの参照をローカル変数に入れとく(⇛圧縮ツールで短縮できる)
  • 可能ならセレクタAPIを使う
  • HTMLCollections.lengthはキャッシュしとく

DOMの追加

DOMフラグメントを使用してドキュメントの更新(reflow/repaint)を1回にする。

var flag = document.createDocumentFragment();
// ...
document.body.appendChild(flag);

DOMの更新

var oldnode = document.getElementById('target'),
    clone = oldnode.cloneNode(true);
// cloneをごちゃごちゃ
oldnode.parentNode.replaceChild(clone, oldnode);

イベントハンドラ

// no bubble
if (e.stopPropagation) {
    e.stopPropagation();
} else if (e.cancelBubble) {
    e.cancelBubble();
}

// prevent default action
if (e.preventDefault) {
    e.preventDefault();
} else if (e.returnValue) {
    e.returnValue = false;
}
<div id="click-wrap">
  <button>1</button>
  <button>2</button>
  <button>3</button>
</div>
// buttonそれぞれにではなくclick-wrapにイベントをセットする場合
var e = e || window.event;
    src = e.target || e.srcElement;
if (src.nodeName.toLowerCase() !=== "button") {
    return:
}

// YUI3を使えば
Y.delegate('click', myHandler, "#click-wrap", "button");

setTimeout

長い処理もsetTimeoutを1msで使えば、UIが固まるってことはない。
でもIEだと1msでも15msだったりするから注意ね。

WebWorkers

var ww = new Worker('my_web_worker.js');
// postMessageでメッセージが送られてくる。ww.postMessageでこっちからも送れる
ww.onmessage = function(event) {
     document.body.innerHTML += "<p>message from the background thread: " + event.data + "</p>";
};

XHR基本パターン

var i, xhr, activeXids = ['MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'];
if (XMLHttpRequest) {
    xhr = new XMLHttpRequest();
} else {
    for (i = 0; i < acriveXids.length; i += 1) {
        try {
            xhr = new ActiveXObject(activeXids[i]);
            break;
        } catch (e) {}
    }
}
xhr.onreadystatechange = function() {
    if (xhr.readyState !=== 4) {
        return false;
    }
    if (xhr.status !=== 200) {
        alert("Error, status code: " + xhr.status);
        return false;
    }
    document.body.innerHTML += "<pre>" + xhr.responseText + "</pre>";
};
xhr.open("GET", "page.html", true);
xhr.send("");

CDN

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.js" type="text/javascript"></script>

src

タグで外部のスクリプトをダウンロードし始めると、そのスクリプトのダウンロード・パース・実行が完了するまで他のダウンロードは止まってしまう。
スクリプトタグを下の方(の手前)に置けばブロックの影響を最小限にできる。

「出社が楽しい経済学」読了

出社が楽しい経済学

出社が楽しい経済学

読みました。
サンクコスト、機会費用といったよく聞く用語があいまいだけど理解できた。

Firefox4でECMAScript5のStrict mode

ココによるとFirefox4(現在4.0b8)で対応してるみたいなんで試してみる。

> function test() {
    "use strict";
    a = 1;
}
undefined
> test();
ReferenceError: assignment to undeclared variable a

> function test() {
    "use strict";
    this.a = 1;
}
undefined
> test();
TypeError: this is undefined

> function test() {
    "use strict";
    var o = {a: 1, a: 2};
}
SyntaxError: property name a appears more than once in object literal

> function test() {
    "use strict";
    with ({}) {
        console.log("Hello");
    }
}
SyntaxError: strict mode code may not contain 'with' statements

「zsh最強シェル入門」読了

zsh最強シェル入門

zsh最強シェル入門

読みました。
.zshrcもごっちゃごちゃだから整理しないとな。

Bitbucketでドットファイル管理

Bitbucketでドットファイルを管理することにしたのでメモメモ。

初期設定・追加

~ $ mkdir dotfiles
~ $ mv .zshrc dotfiles
~ $ ln -s .zshrc dotfiles/.zshrc
~ $ cd dotfiles
dotfiles $ hg init
dotfiles $ hg add .zshrc
dotfiles $ hg commit
dotfiles $ hg push ssh://hg@bitbucket.org/user_name/dotfiles

初期取得

~ $ hg clone ssh://hg@bitbucket.org/user_name/dotfiles

変更反映

dotfiles $ hg push

更新取得

dotfiles $ hg pull -u