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
- 作者: Stoyan Stefanov
- 出版社/メーカー: O'Reilly Media
- 発売日: 2010/10/01
- メディア: ペーパーバック
- 購入: 2人 クリック: 79回
- この商品を含むブログ (5件) を見る
読みました。
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フラグメントを使用してドキュメントの更新(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>