uzullaがブログ

uzullaがブログです。

CoffeeScriptで、newするときのプロパティ変数の初期化ってどーなってんの?

なんか、CoffeeScriptで、あるクラスからいくつもインスタンスをつくって色んな処理をさせていたのだけれど、
なんか変数が共有されているというか、変数の参照がわたっているというか…なんかへんな挙動していて困る。

例になるクラス

class Chain
    queue: []
    
    test: ()->
        @queue.push('A')

実行すると…

c = new Chain
c.test()
console.log c.queue

c = new Chain
c.test()
console.log c.queue

を実行すると、両方とも、Aがでるだけだと思うんだけど、A,Aと出る…


なんだこれ、cに代入できてないの?って思って以下のコードを実行しても

c = new Chain
c.test()
console.log c.queue

d = new Chain
d.test()
console.log d.queue

A,Aと出る…


勿論

c = new Chain
c.test()
console.log c.queue
setTimeout(
    () ->
        d = new Chain
        d.test()
        console.log d.queue
        console.log c.queue
    3000
)

でもA,Aと出る…なんぞ!??!

こう書くと直る

class Chain
    queue: []

    constructor: () ->
        @queue=[]

    test: ()->
        @queue.push('A')

えっ、これってもしかして

Coffeescriptのクラスのプロパティ変数って、初期化が必須なの?(;´Д`)
コンストラクタで宣言しなおさないと、暗黙のウチに共有されちゃうの?
そういうもんなの??

細かい事言えば

プリミティブ変数はそのままでもバグらない。
配列、オブジェクトなどといった配列渡しされるやつだけ影響するぽい。
まあ想像はつくというか、newするときに適切にコピーしてない。
もしかして、これがJSのOOPの常識なのかもしれないけど、CoffeescriptでJSのOOP始めた自分は、なかなかびっくりした。

さらにどうでもいいオマケとして

上のコード、Safariで実行すると、最初の方もA,Aって出てウケる。
途中のsetTimeoutでタイミングずらした奴は、最初の方ちゃんとAだけがでるから、Safariのconsole.logが凄い非同期な感じなんだと思う…が、それもどうなんだ?