Javascriptのオブジェクト指向
「Javascriptのオブジェクト指向は気持ち悪い!」
みたいな意見を聞くことがあるけれど、
そういうのはたいてい慣れの問題だと思っています。
「オレオレオブジェクト指向」を作って使っちゃうのも、
自分ひとりだけならいいけど多人数が見るコードでやるのは迷惑かなと。
だいたい「オレオレクラス」を分かりやすいと思っているのは作った人だけだったり。。。
でもJavascriptのオブジェクト指向に問題があるのは事実だし
対策は必要なので自分がベストだと思っている方法を書いておきます。
newをつけなくても呼び出せちゃう問題
function Point(x, y){ this.x = x; this.y = y; } var o = new Point(0, 0); // 問題なし var p1 = Point(1, 1); // p1はundefinedだし、グローバルオブジェクトが汚染される!
この場合、Pointコンストラクタの一行目に
console.assert(this instanceof Point, 'newをつけずに呼び出された可能性があります');
みたいに書いておくのがいいと思います。
Node.jsではエラーになるし、ブラウザでもコンソールを見ればわかります。
この問題への対策として
if(!(this instanceof Point)) return new Point(x, y);
みたいなコードも見るけれどあまりよくないです。
根本的な解決(newを付けてコールさせるべき)になっていないうえに、
可変長の引数を取る場合Function.prototype.bindを使う必要があって面倒臭さいです。
prototype継承とインスタンスの問題
問題のないprototypeチェーンを作るにはこのようにする必要があります。
毎回こんなことをやるのは面倒です。
だからといってオレオレクラスを作るのはよくないので、
コンストラクタに何もさせないことにします。
コンストラクタが何もしないのならば周りくどいことをする必要はありません。
function Point(){ console.assert(this instanceof Point, 'newをつけずに呼び出された可能性があります'); } Point.prototype.init = function(x, y){ // 初期化はこの関数で this.x = x; this.y = y; } Point2.prototype = new Point(); function Point2(){ Point.call(this); } var p1 = new Point(); p1.init(1, 2); // 初期化 var p2 = new Point2(); p2.init(1, 2); // 初期化
これはこれでデメリットがないとは言い切れませんが、大きな問題はないと思います。
DOMの操作で似たようなことをしますし。おすし。
var event = document.createEvent('Events'); event.initEvent('eventtype', false, false); // 初期化
ぶっちゃけprototypeって打つのメンドクサイ問題
Object.definePropertiesを使えるならば使いましょう。
prototypeって打つのは1回だけだし、for( in ) で列挙されないようにできます。
書き換え不能にもできます。
一石三鳥です。
Object.defineProperties(Point.prototype, { init: { value: function(x, y){ this.x = x; this.y = y; } }, distance: { value: function(otherPoint){ var x = otherPoint.x - this.x, y = otherPoint.y - this.y; return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); } } });
でも、そもそもfunctionって打つのも面倒なので、
根本的に解決したいなら補完してくれるエディタを使うべきだったり。(Aptanaとか)
まとめ
「オレオレオブジェクト指向」で作ったコードを読めるのは「今」の自分だけかもしれません。
すみやかにやめたらいいと思います。
どうしても素のJavaScriptが嫌なら「traceur」みたいなものがあるんだから、
そっちを使えばいいんじゃないでしょうか。
IE9RCを試してみた
IE9がRCになったようなので開発者ツールとかを軽く試してみた。
Javascript
>> Object.defineProperty function defineProperty() { [native code] } ウォッチ対象に追加 >> Object.defineProperties function defineProperties() { [native code] } ウォッチ対象に追加 >> [] {...} ウォッチ対象に追加 >> [].map function map() { [native code] } ウォッチ対象に追加 >> [].filter function filter() { [native code] } ウォッチ対象に追加 >> [].forEach function forEach() { [native code] } ウォッチ対象に追加 >> window.addEventListener function addEventListener() { [native code] } ウォッチ対象に追加 >> document.addEventListener('click', function(){console.log('clicked')}, false) ログ: clicked ログ: clicked ログ: clicked
consoleとか、よく使う関数とかが定義されていて嬉しい。
__defineGetter__とかは使えないみたいだけど
Object.defineProperty()があるから問題ない。
まとめ
HTMLを書く側としてはいろいろ楽になるんじゃないかと思う。
どうなるかは、まだわからんけど。
Vista SP2以降じゃないと使えないから、XPを使っている人はIE8を使い続ける事になるし。
XP邪魔。。。
あと、バレンタインチョコ欲しい!
欲しいのはiPod touch。(一番欲しいのはMacbook Airだけど)
はてなさんじゃなくていいから誰かください。
Gitのコマンドにエイリアスを設定した
gitのコマンドってやたらと長い物が多い。
(checkoutとかbranchとかcherry-pickとか)
長いと打ち間違えも多くなるし、どうにかならないかと思って調べたら、
エイリアスを設定できることがわかった。
もしかして知らなかったのは自分だけ?
git config --global alias.co checkout
ってやっておくと
git co master
でmasterブランチにチェックアウトできる。
タイプ数が6文字も減っている。
1日1回checkoutする人なら、なんと1年で2190文字もタイプ数が減る。
とりあえず、よく使うものを設定しておいた。
git config --global alias.co checkout git config --global alias.lo "log --oneline --reverse" git config --global alias.pick cherry-pick
でもあんまり短すぎても、よくわかんなくなるし程々にしたほうがよさそう。
Javascriptでいい感じにプロトタイプを継承する
Javascriptでプロトタイプを継承するには
function newClass(){ superClass.apply(this, arguments); } newClass.prototype = new superClass(); // superClassを継承 var newObject = new newClass(); console.log(newObject instanceof superClass); // true
こんなコードを書けばいいわけだけど、
これだとsuperClassオブジェクトを作っているところがスマートじゃない。
newClass.prototype = superClass.prototype; // superClassを継承
これだと余計なオブジェクトはつくらないけど、
newClassのprototypeを拡張するとsuperClassのprototypeも拡張されてしまう。
というわけで
newClass.prototype = (function(C){ C.prototype = superClass.prototype; // superClassを継承 return new C(); })(function(){});
こんな書き方をする必要がある。
さらに今はやり(?)のObject.definePropertiesを使って
newClass.prototype = Object.defineProperties((function(C){ C.prototype = superClass.prototype; // superClassを継承 return new C(); })(function(){}), { methodA: { value: function(){ // methodA } } });
とするとfor(〜 in 〜)したときに余計なプロパティを列挙しなくなる。
Chromeで、すでに使用可能。
拡張を作るときに活用できる。
ただしArrayの拡張はこれでもうまくいかない。
myArray = new MyArray(); myArray[100] = 100;
と、代入したときにlengthが101にならない等の問題がある。
たぶん完全にArrayを拡張する方法は(いまのところ)ない。
擬似要素でアニメーションが効かない
Python + goo.gl でURLを短縮する
この記事が元ネタ。なぜか全然動かないコードだったので勝手に修正。
動作確認はWindows Vista + Python 2.5。
simplejsonがないとImportErrorって言われて怒られると思います。
googl.py
#!/usr/bin/env python def shorten(url): from urllib2 import urlopen, Request, HTTPError from urllib import quote from simplejson import loads try: req = Request('http://goo.gl/api/url', 'url=%s' % quote(url)) try: urlopen(req) except HTTPError, e: if e.code == 201: res = e.read() else: raise j = loads(res) return j['short_url'] except: raise Exception('Unknown eror forming short URL.') if __name__ == '__main__': from sys import argv print shorten(argv[1])