この記事を読んで、Chromeのconsole.logの動きが謎すぎる気がして確認してみました。
CoffeeScriptで、newするときのプロパティ変数の初期化ってどーなってんの? - uzullaがブログ
検証
ソースコード
var a = [];
a.push('A');
console.log(a);
a.push('A');
console.log(a);
これをChromeのDeveloper toolのコンソールで実行してみました。
期待する出力
["A"]
["A", "A"]
実際の出力
["A", "A"]
["A", "A"]
調べてみた
console.log lazy等でググるとStackoverflow等のサイトがでてきた。
Is Chrome's JavaScript console lazy about evaluating arrays? - Stack Overflow
javascript - Bizarre console.log behaviour in Chrome Developer Tools - Stack Overflow
なるほど。Webkit特有なのかもしれません。
console.logにオブジェクトを渡すと、console.logはそのオブジェクトの内容を出力します。
console.logが出力する準備をしている間にそのオブジェクトに変更を加えると変更後のオブジェクトの内容が出力されると。
シンプルな解決方法として
- JSON.stringify
- toString
- slice (配列の場合)
等のメソッドや関数を使って別のオブジェクトを作成してから渡す方法が挙げられてますね。
ちなみに
Coffeescriptのクラスのプロパティ変数って、初期化が必須なの?(;´Д`)
コンストラクタで宣言しなおさないと、暗黙のウチに共有されちゃうの?
そういうもんなの??
JavaScriptのprototype継承ですね。
class Chain
queue: []
test: -> @queue.push "A"
は
var Chain;
Chain = (function() {
function Chain() {}
Chain.prototype.queue = [];
Chain.prototype.test = function() {
return this.queue.push("A");
};
return Chain;
})();
JavaScriptになるとこうなっています。
Chainクラスはprototypeというオブジェクトを持っています。(以下prototypeオブジェクト)
CoffeeScriptのクラスのメソッド等はこのprototypeオブジェクトのプロパティに定義されます。
Chainクラスのインスタンスはprototypeオブジェクトへの参照を持っています。
Chainクラスのインスタンスからqueueプロパティにアクセスするとき
- まずインスタンス自身がqueueプロパティを持っていないか調べる
- 持っていなければクラスのprototypeオブジェクトにqueueがないか調べる。
- クラスのprototypeオブジェクトにもqueueプロパティがなければ更に継承元のクラスを辿って行く
という感じになってます。
インスタンス自身がプロパティを持っているかどうか調べるためにはhasOwnPropertyを使います。
例
class Chain
queue: []
test: -> @queue.push "A"
c = new Chain
console.log "before c.queue = []"
console.log c.hasOwnProperty "queue"
c.queue = []
console.log "after c.queue = []"
console.log c.hasOwnProperty "queue"
実行結果
before c.queue = []
false
after c.queue = []
true
queueプロパティに配列を代入するまで、Chainクラスのインスタンスは自分自身のqueueプロパティを持ちません。
そのため、全てのインスタンスがChainクラスのprototypeオブジェクトのqueueプロパティを参照しています。
なのでtestメソッドの中でthis.queue.push("A")を呼び出すと、Chainクラスのprototypeオブジェクトのqueueプロパティが変更されるわけです。
こう書くとなおるわけ
例
class Chain
constructor: -> @queue = []
console.log "c = new Chain"
c = new Chain
console.log "c.hasOwnProperty 'queue': #{c.hasOwnProperty 'queue'}"
JavaScriptになると
var Chain, c;
Chain = (function() {
function Chain() {
this.queue = [];
}
return Chain;
})();
console.log("c = new Chain");
c = new Chain;
console.log("c.hasOwnProperty 'queue': " + (c.hasOwnProperty('queue')));
実行結果
c = new Chain
c.hasOwnProperty 'queue': true
コンストラクタの中で以下のコードを呼び出すことで、インスタンス自身のプロパティとしてqueueを定義しています。
this.queue = [];
インスタンス自身のプロパティなので、ほかのインスタンスのqueueを変更しても、関係ない。
そんな感じ。
まとめ
- Webkitのconsole.logはオブジェクトが表示されるまでにディレイがあって、その途中でオブジェクトの中身を変更すると、変更後の内容が出力される
- CoffeeScriptのクラスの仕組みについて知るためにはJavaScriptのプロトタイプチェーン等に関する知識が必要。
JavaScriptについて勉強するにはパーフェクトJavaScriptがお勧めです。
パーフェクトJavaScript (PERFECT SERIES 4)
- 作者: 井上誠一郎,土江拓郎,浜辺将太
- 出版社/メーカー: 技術評論社
- 発売日: 2011/09/23
- メディア: 大型本
- 購入: 17人 クリック: 407回
- この商品を含むブログ (12件) を見る
0 件のコメント:
コメントを投稿