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.

JavaScriptでscala.util.control.Breaksのようなもの

Posted at

Array.prototype.forEachは途中でbreakしたくなっても抜けられない。
Array.prototype.someを使うという方法もあるみたいですが、それは色々とあれなので…

とりあえず、Scala風にBreaksクラスを作ってみた。(scala.util.control.Breaks

breaks.js
/**
 * scala.util.control.Breaksのようなもの。
 * @constructor
 */
function Breaks() {
  if (!(this instanceof Breaks)) return new Breaks();

  var
  value,
  breaking = {};

  /**
   * ループを抜ける
   * @name breaks
   * @fieldOf Breaks
   */
  Object.defineProperty(this, 'breaks', {
    get: function () {
      throw breaking;
    },
    set: function (val) {
      value = val;
      throw breaking;
    },
  });

  /**
   * 抜けられるしキャッチできるブロック
   * @param {Function} procedure 実行するブロック
   * @return {Object} catchBreakを持ったオブジェクト
   */
  this.tryBreakable = function (procedure) {
    var
    breaks = this;
    return {
      catchBreak: function (onBreak) {
        value = undefined;
        try {
          procedure(breaks);
        } catch(e) {
          if (e !== breaking) throw e;
          onBreak(value);
        }
      },
    };
  };
}

/**
 * 抜けられるブロック
 * @param {Function} procedure 実行するブロック
 */
Breaks.prototype.breakable = function (procedure) {
  this.tryBreakable(procedure).catchBreak(function () { /* noop */ });
};

/**
 * インスタンスをわざわざ作るのが面倒な人向け
 * @param {Function} procedure 実行するブロック
 */
Breaks.breakable = function (procedure) {
  (new Breaks).breakable(procedure);
}

コードを見れば一目瞭然だけど、scala.util.control.Breaks同様に特定の例外を投げてそれをキャッチすることでbreakを実現してる。

使い方はこうなる。

breaks-usage.js
Breaks.breakable(function (b) {
  [1, 2, 3, 4, 5].forEach(function (x) {
    if (x === 3) b.breaks;
    console.log(x);
  });
});

結構良い感じだと思う。

実は、最初はCoffeeScriptで書いてたんだけど、よく考えたらCoffeeScriptには優秀なfor文があるから必要ないなー、と思ったりしてました。

一応その記録も貼っておきます。

breaks.coffee
getter = (obj, name, func) ->
  Object.defineProperty obj, name, 
    get: func

class Breaks
  constructor: ->
    breaking = {}
    getter @, 'breaks', -> throw breaking
    @breakable = (procedure) ->
      try
        procedure @
      catch e
        throw e if e isnt breaking
  @breakable: (procedure) ->
    (new Breaks).breakable procedure

Breaks.breakable (b) ->
  [1..10].forEach (x) ->
    b.breaks if x is 5
    console.log x

これはこれでいいと思ったんだけどな―

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?