3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

CoffeeScriptのfor-inループで、一時変数が一時変数じゃない件

Last updated at Posted at 2014-07-07

問題

問題のコード

a = [ {}, {} ]
b = [ "a", "b" ]

for s,i in b
  a[i].gets = ->(s)

console.log a[0].gets()
console.log a[1].gets()

展開される奴

// Generated by CoffeeScript 1.7.1
var a, b, i, s, _i, _len;

a = [{}, {}];

b = ["a", "b"];

for (i = _i = 0, _len = b.length; _i < _len; i = ++_i) {
  s = b[i];
  a[i].gets = function() {
    return s;
  };
}

console.log(a[0].gets());

console.log(a[1].gets());

期待する出力

a
b

現実

b
b

原因

javascriptは変数のスコープを区切る方法がfunctionしかないらしい。そしてcoffeescriptは変数をスコープの一番最初で宣言する。たとえfor-inの一時変数だとしても。ひどいよ。

解決

forの中で一時関数を作って実行すればうまくいくって言ってた。

a = [ {}, {} ]
b = [ "a", "b" ]

for s,i in b
  do (s,i) ->
    a[i].gets = ->(s)


console.log a[0].gets()
console.log a[1].gets()

感想

なんでforeach死体だけなのに、変な行とインデント挟まにゃならんのだ。coffeescriptはjavascriptをrubyライクに書けるみたいなノリなら(そうなのかどうかは知らないです)、デフォをこっちにして欲しいところです。

ちなみに

JQueryのeachが、「index, value」なのが気に入りません。thisで参照するのは可読性の意味で論外として、eachをするときは基本indexではなくvalueに用事があるのに、いちいちindexを書く手間と変数名を考える手間がひどい。あとArrayにeachが無いのも辛い。

このへんは、最新のブラウザではArray#forEachがあるらしいので、古いブラウザを切り捨てるか互換ライブラリを入れるかそれを使いたいところです。遅いらしいですけど。でもそんなのしたくないからCoffee使ってるのに。

追記

javascriptのクラス拡張がどれくらい怖いか経験少ないのでわからないけど、こうすれば見た目綺麗になれる。

Array.prototype.each = (callback)->
  for v,i in this
    callback(v,i)

参考

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?