無理矢理メソッドチェーン
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ なんでもかんでもメソッドチェーンした人必見?
◆ 人によっては関数合成のほうが好みかも
◆ 人によっては関数合成のほうが好みかも
メソッドチェーンしたい
汎用的な機能だとこんな感じにプロトタイプに追加しておく事が多いと思いますString.prototype.startWith = function(str){
return this.indexOf(str) === 0
}
String.prototype.contain = function(x){
return this.indexOf(x) >= 0
}
Array.prototype.last = function(){
return this[this.length - 1]
}
Array.prototype.first = function(){
return this[0]
}
Array.prototype.contain = function(x){
return this.indexOf(x) >= 0
}
ですが ここでしか使わない といえるような処理をプロトタイプに入れてしまうのは抵抗がありますreturn this.indexOf(str) === 0
}
String.prototype.contain = function(x){
return this.indexOf(x) >= 0
}
Array.prototype.last = function(){
return this[this.length - 1]
}
Array.prototype.first = function(){
return this[0]
}
Array.prototype.contain = function(x){
return this.indexOf(x) >= 0
}
例えばこんなのです
function gettag(text){
return text.trim().match(/^<\s*([0-9a-z]+?)/i)
}
function isColorCode(text){
return !!text.match(/^\#([0-9a-f]{3}|[0-9a-f]{6})$/i)
}
funtion makeAttrStr(attrs){
return Object.keys(attrs).map(function(key){
return key + '="' + attrs[key] + '"'
}).join(" ")
}
return text.trim().match(/^<\s*([0-9a-z]+?)/i)
}
function isColorCode(text){
return !!text.match(/^\#([0-9a-f]{3}|[0-9a-f]{6})$/i)
}
funtion makeAttrStr(attrs){
return Object.keys(attrs).map(function(key){
return key + '="' + attrs[key] + '"'
}).join(" ")
}
真ん中のカラーコードなら まだいいかなと思うような思わないようなですが下のやつなんてかなり限られた時にしかつかわないですし こういうのがすべてプロトタイプに書いてるのはいやです
ですが 1つの式が長くなってくると 関数だと前後をカッコで囲むので見づらくなってしまいます
いい感じに全部をメソッドチェーンできるといいのに…
関数呼び出し用のメソッドを作る
直接プロトタイプに入れるから気持ち悪いので 指定した関数を自分を引数にして実行するメソッドをObjectのプロトタイプにつけてみましたObject.prototype.callBy = function(fn /*args*/){
var args = [].slice.call(arguments,1)
args.unshift(this)
return fn.apply(null, args)
}
var args = [].slice.call(arguments,1)
args.unshift(this)
return fn.apply(null, args)
}
こんな感じで使えます
この処理自体に特に意味は無いです
[255,0,128].map(function(e){return e.toString(16)}).join("").callBy(parseInt, 16)
function plus(a, b){
return a + b
}
function mod(a, b){
return a % b
}
"123.456".callBy(parseInt).callBy(plus, 20).callBy(mod, 5)
.callBy(Math.sqrt).toString().callBy(JSON.stringify)
function plus(a, b){
return a + b
}
function mod(a, b){
return a % b
}
"123.456".callBy(parseInt).callBy(plus, 20).callBy(mod, 5)
.callBy(Math.sqrt).toString().callBy(JSON.stringify)
上側は 式がながーくなってきて最後に parseIntしたい って思った時に最初にカーソル戻して parseInt( を書いてカーソル最後に戻して ) を書くのっていやですよね
これを使うことで最後に .callBy(parseInt) で済みます!
.callBy を呼び出したthisが 呼び出す関数の第一引数になります
.callBy の2つめ以降の引数は呼び出す関数の2つめ以降の引数になります
下側を普通にかくとこうなります
JSON.stringify(Math.sqrt((parseInt("123.456") + 20) % 5).toString())
コードはこっちのほうが短いですが 流れがわかりづらくカッコが多くていやですplusとmodも関数にすると
JSON.stringify(Math.sqrt(mod(plus(parseInt("123.456"), 20), 5)).toString())
もうよみたくない・・・見やすくするだけなら関数合成という方法も
function composite(){
var args = [].slice.call(arguments)
return function(v){
for(var i=0;i<args.length;i++){
v = args[i](v)
}
return v
}
}
function plus20(a){
return plus(a, 20)
}
function mod5(a){
return mod(a, 5)
}
function toString(a){
return a.toString()
}
composite(parseInt, plus20, mod5, Math.sqrt, toString, JSON.stringify)("123.456")
var args = [].slice.call(arguments)
return function(v){
for(var i=0;i<args.length;i++){
v = args[i](v)
}
return v
}
}
function plus20(a){
return plus(a, 20)
}
function mod5(a){
return mod(a, 5)
}
function toString(a){
return a.toString()
}
composite(parseInt, plus20, mod5, Math.sqrt, toString, JSON.stringify)("123.456")
読むだけならすごく見やすいですね!
ですが 最初に "123.456" を書いて順番に関数を書いていきたいと考えるとメソッドチェーンのほうがいいのかなと思ってしまいます
plus20 や mod5 と言った関数を用意して すべての関数が引数1つになるようにしないといけないですし toString のようなメソッドも関数化しないとです
注意
Object.prototype.callBy = function(fn /*args*/){
var args = [].slice.call(arguments,1)
args.unshift(this)
return fn.apply(null, args)
}
ですがvar args = [].slice.call(arguments,1)
args.unshift(this)
return fn.apply(null, args)
}
Object.prototype.callBy = function(fn /*args*/){
var args = arguments
args[0] = this
return fn.apply(null, args)
}
だと動きませんvar args = arguments
args[0] = this
return fn.apply(null, args)
}
この辺で詳しく書きましたけどargs[0]が書き換えられるとfnまで変わってしまいます
なのでfn.applyのfnが関数でなくthisになっていてthisが関数でないとapplyがないとエラーになります