118
120

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でメソッドチェーンを作る

Last updated at Posted at 2014-12-04

はじめに

jQueryのメソッドチェーンはとても便利で、自分もよく使っていますが「作り方」が
よく分かっていなかったので実際に簡単なサンプルを作ってみました。
知っている人にとっては簡単だと思いますが、自分のように知らない人に少しでも
お役に立てれば幸いです(`・ω・´)ゞ

元記事 http://sawapi.hatenablog.com/entry/2014/12/05/004710

そもそもメソッドチェーンとは

メソッドチェーンとは、メソッドをつなげて処理することをいいます。
例えばjQueryだと、

jQuery( 'div' ).width( 100 ).height( 100 ).css( {
   backgroundColor: '#000'
} );

といったようにwidth, height, cssのメソッドをつなげて書くことができます。
もし、jQueryがメソッドチェーンに対応していないと以下の様な形で書かないといけません。

var div = new jQuery( 'div' ); // 内部的にnewしてるのでつけるかどうか微妙だけど。
div.width( 100 );
div.height( 100 );
div.css( {
    backgroundColor: '#000'
} );

一度変数に入れることが必須となるので少しめんどくさいですね。

メソッドチェーンの基本的な作り方

作り方の前にまずは、文字列をappendメソッドで連結し、getメソッドで連結した文字列を取得する
メソッドチェーンに対応していないクラスを作ってみます。

var builder = function( str ) {
    
    if ( typeof str === 'undefined' ) {
    
        this._str = '';

    } else {

        this._str = '' + str; // 型変換
    }
};

builder.prototype = {

    // 文字連結
    append: function( str ) {
        
        this._str += '' + str;   
    }, 

    // 連結した文字列を返す
    get: function() {
        
        return this._str;
    }
}

上記のクラスを使うと

var b = new builder();
b.append( 'hoge' );
b.append( 'fuga' );
b.append( 'moge' );
var result = b.get();
console.log( result );
// > hogefugamoge

このような形で書くことになります。
さて、このbuilderクラスをメソッドチェーンできるようにしてみましょう。

var builder = function( str ) {
    
    if ( typeof str === 'undefined' ) {
    
        this._str = '';

    } else {

        this._str = '' + str; // 型変換
    }
};

builder.prototype = {

    // 文字連結
    append: function( str ) {
        
        this._str += '' + str;
        // 自分自身を返す
        return this; 
    }, 

    // 連結した文字列を返す
    get: function() {
        
        return this._str;
    }
}

このクラスは以下のように利用することができます。

var result = new builder().append( 'hoge' ).append( 'fuga' ).append( 'moge' ).get();
console.log( result );
// > hogefugamoge

メソッドをつなげて書くことが出来ました!
どこが変わったかというと、appendメソッドで「return this;」として自分自身を返してあげています。
これだけでメソッドチェーンに対応できるんですね!
ただし、これではbuilderの前にnewがついてしまっています。newを取る方法はいろいろあるような
気がしますが、ここではjQueryのやり方にならって書いてみます。

「new」を取る

では、実際にnewをつけない書き方で書いてみましょう。

var builder = function( str ) {
    
    // インスタンスをbuilderの中で生成
    return new builder.prototype.init( str );
};

builder.prototype = {

    // 初期化メソッド( initという名前じゃなくてもいいです )
    init: function( str ) {

        // コンストラクタ的なのをbuilder.prototype.initの中に書く
        if ( typeof str === 'undefined' ) {
    
            this._str = '';

        } else {

            this._str = '' + str; // 型変換
        }
    }, 

    // 文字連結
    append: function( str ) {
        
        this._str += '' + str;
        // 自分自身を返す
        return this; 
    }, 

    // 連結した文字列を返す
    get: function() {
        
        return this._str;
    }
}

// builder.initのprototypeにbuilderのprototypeを持たせる
builder.init.prototype = builder.prototype;

これでnewをつけずに書くことができます!

var result = builder().append( 'hoge' ).append( 'fuga' ).append( 'moge' ).get();
console.log( result );
// > hogefugamoge

ポイントとしては、builderの中で書いていたコンストラクタ的な処理を自身のprototypeの中に
作った関数( ここではinit )にやらせてしまい、その関数のprototypeにbuilderのprototypeを
持たせ、builderの中でインスタンスを生成することでnewを省略することができます。
さて、ここまで分かったところで簡単な電卓クラスを作ってみます。

簡易電卓クラス

たす、ひく、かける、わるのできる簡単な電卓クラスを作ります。
ただし、カッコのついた計算もできるように少し工夫します。

!function( window ) {
// 簡易電卓クラス
// 3 * ( 1 + 3 ) / 6
// みたいな式を
// calc( 3 ).multiply( calc( 1 ).plus( 3 ) ).divide( 6 ).get();
// こんな感じで使えるように
var calc = function( num ) {

    // calcクラスであればそのまま返す
	if ( num instanceof calc ) {

		return num;
	}

    // 数字以外は0にする
	if ( typeof num !== 'number' ) {

		num = 0;
	}
	// インスタンス生成
	return new calc.prototype.init( num );
}

calc.prototype = {

    // コンストラクタ
	init: function( num ) {

		this._num = num;
	}, 

    // たす
	plus: function( num ) {

		this._num += calc( num ).get();
		return this;
	}, 

	// ひく
	minus: function( num ) {

		this._num -= calc( num ).get();
		return this;
	}, 

	// かける
	multiply: function( num ) {

		this._num *= calc( num ).get();
		return this;
	}, 

    // わる( 0でわることを考慮してない )
	divide: function( num ) {

		this._num /= calc( num ).get();
		return this;
	}, 

    // 取得
	get: function() {

		return this._num;
	}
}

// initのprototypeにcalcのprototypeをつっこむ
calc.prototype.init.prototype  = calc.prototype;

window.calc = calc;

}( window );

さて、このクラスを使って簡単な計算をしてみましょう。

// 10 + 20
calc( 10 ).plus( 20 ).get();
// > 30

// ( 9 - 7 ) * 5
calc( 9 ).minus( 7 ).multiply( 5 ).get();
// > 10

// 3 * ( 1 + 3 ) / 6
// 括弧内の計算はcalcでおこないそのオブジェクト自体を引数に指定する
calc( 3 ).multiply( calc( 1 ).plus( 3 ) ).divide( 6 ).get(); 
// > 2

ちょっと工夫すると括弧付きの計算もできるようになりました!

まとめ

メソッドチェーンするには、メソッドの最後に「return this;」とつけて自分自身を返すことで
簡単に作ることができました。使いどころはライブラリとか作らない限りあまりないかもしれませんが覚えておいて損はなさそうです!
calc.jsをgistにあげました。

118
120
2

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
118
120

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?