1
1

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.

_.forEachをCoffeeScriptで使うときの注意点

Posted at

tl;dr

もったいぶって書いてますが、CoffeeScriptの関数の最後の値がなんであってもreturnされます。
_.forEachであればコールバックでreturn falseされると巡回が終わってしまう。これに最後の行にbool = false的なものを書くとreturn bool = falseとなり、意図せずfalsereturnされてしまうので、気を付けましょう。

lodashの_.forEachがすべての要素を巡回しない問題

例えば全部のactiveプロパティをfalseにしようとします。

example.coffee
describe '_.forEach', ->
    objects = null

    beforeEach ->
        objects = [
            id: '1'
            active: true
        ,
            id: '2'
            active: true
        ,
            id: '3'
            active: true
        ]

case1

example.coffee
    it 'should make all inactive', ->
        _.forEach objects, (obj)->
            obj.active = false

        expect object[0].active
        .toBe false
        expect object[1].active
        .toBe false
        expect object[2].active
        .toBe false

あれ?失敗するぞ。

case2

example.coffee
    it 'should sweep all element', ->
        count = 0
        _.forEach objects, (obj)->
            count = count + 1
            obj.active = false

        expect count
        .toBe 3

あれれ?また失敗するぞ。

case2を修正

example.coffee
    it 'should sweep all element', ->
        count = 0
        _.forEach objects, (obj)->
            obj.active = false
            count = count + 1

        expect count
        .toBe 3        

おっ、成功した。
count = count + 1obj.active = falseを入れ替えると結果が変わる。
ああ、いつでも忘れてはいけないこの仕様……

JavaScriptを見てみる

example.js
  it('should sweep all element', function() {
    var count;
    count = 0;
    _.forEach(objects, function(obj) {
      count = count + 1;
      return obj.active = false;
    });
    return expect(count).toBe(3);
  });
example.js
  it('should sweep all element', function() {
    var count;
    count = 0;
    _.forEach(objects, function(obj) {
      obj.active = false;
      return count = count + 1;
    });
    return expect(count).toBe(3);
  });

そう、犯人はreturn obj.active = false;です。

lodashのドキュメントに書いてあります

Iterates over elements of collection invoking iteratee for each element. The iteratee is bound to thisArg and invoked with three arguments; (value, index|key, collection). Iterator functions may exit iteration early by explicitly returning false.

https://lodash.com/docs#forEach

_.forEachのコールバックでreturn falseすると巡回を止めてしまいます。

example.coffee
    it 'should make all inactive', ->
        _.forEach objects, (obj)->
            obj.active = false
            true

        expect objects[0].active
        .toBe false
        expect objects[1].active
        .toBe false
        expect objects[2].active
        .toBe false

これでOK。

ちなみに

jQuery$.eachも同じ仕様のようですが、AngularJSangular.forEachは巡回をやめないようです(!!)

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?