2015-07-22 274 views
0

在下面你的函數cat可以調用eatplay功能的情況下直接實例化一個新的cat對象,這是由值傳遞從功能cat.eatcat.play函數來獲取狀況證明。複製下劃線的鏈方法風格

var cat = function(obj){ 
    // if (obj instanceof cat) return obj; 
    // if (!(this instanceof cat)) return new cat(obj); 
    // this.catwrapped = obj; 
} 

cat.eat = function(food){ 
    if(food == "tuna") return 95 
    if(food == "milk") return 35 
    return 0 
} 

cat.play = function(energy){ 
    if(energy < 50) return 0 
    return 100 
} 

var energy = cat.eat("tuna") 
var status = cat.play(energy) 

console.log(status) // 100 

我試圖保持此功能並添加下劃線樣式鏈接。所以你可以做到以下幾點。這是如何實現的?

cat.day = function(obj){ 
    var instance = cat(obj); 
    // instance._chain = true; 
    return instance; 
} 

var status = cat.day() 
    .eat("tuna") 
    .play() 
    .status() 

console.log(status) // should log 100 

那是我必須catcat.day,使這項工作最少的代碼?

+0

哇,剛剛發現[強調遍歷自身](https://github.com/jashkenas/underscore/blob/master/underscore.js#L1550)創建所有的'原型'。 – ThomasReggi

+0

我想我錯了,它只是將數組操作添加到下劃線庫。 – ThomasReggi

+0

你的功能*做任何事情嗎?如果他們沒有副作用,可以完全忽略對他們的呼叫。他們不應該至少改變貓實例嗎?目前,你的功能只返回一些數字。下一個函數返回一個不同的數字,沒有任何關聯它們的東西。 Chaining在這裏似乎毫無用處。 – Bergi

回答

0

我創建了一個NPM模塊underscore-chainable完成這一點。

npm install underscore-chainable 

然後

var _ = require("underscore") 
_.mixin(require("underscore-chainable")) 

var cat = _.makeChainable() // make the `cat` object chainable 

cat.eat = function(food){ 
    if(food == "tuna") return 95 
    if(food == "milk") return 35 
    return 0 
} 

cat.play = function(energy){ 
    if(energy < 50) return 0 
    return 100 
} 

_.extendChainable(cat) // extend the chainablity 

// adds `.chain` and `.value` 

var energy = cat.eat("tuna") 
var status = cat.play(energy) 

console.log(status) // 100 

var status = cat 
    .chain("tuna") 
    .eat() 
    .play() 
    .value() 

console.log(status) // 100 
0

您需要返回對象的指針,以便能夠執行鏈來電:

cat.play = function(energy){ 
    // do something with energy 
    return cat 
} 

cat.eat = function(food){ 
    // do something with food 
    return cat 
} 

var status = cat.day() 
    .eat("tuna") 
    .play() 
    .status() 

由於您使用的是不同的目的回報(後忽略它),你需要重新考慮你的程序算法

更新。你可以創造什麼將執行任務或返回從參數取決於數據的功能:

var energy = 0; 
cat.eat = function(v) { 
    // return something on empty call 
    if (!arguments.length) return energy 
    // process passed data 
    energy += v 
    // return cat object to allow chaincals 
    return cat 
} 

在這種情況下cat.eat(10)將允許你進行通話鏈,而cat.eat()將回報你的價值,儲存在能源

Update2:你的函數不會改變任何內部變量,所以任何數據都會在一個標準的鏈式調用中丟失。你做什麼,你需要一個管道,並將一個功能直接輸出到另一個輸入。有方式如何做到這一點的數字:

你可以嘗試使用下劃線減少功能:

var status = _.reduce([cat.play, cat.eat], function(status, f){ return f(status); }, "tuna"); 

或者你也可以直接打電話給他們:

cat.status(cat.play(cat.eat("tuna"))) 

如果創建內部變量存儲能量,你甚至可以調用下劃線鏈:

var cat = function() { 
    this.energy = 0; 
} 

cat.eat = function(food){ 
    if (food == "tuna") cat.energy = 95 
    else if(food == "milk") cat.energy = 35 
    else cat.energy = 0 
} 

cat.play = function(){ 
    if(cat.energy < 50) cat.energy = 0 
    else cat.energy = 100 
} 

var status = _.chain(cat) 
    .eat("tuna") 
    .play() 
    .value() 
    .energy 

但它似乎有點冗餘t

+0

Underscore在每個函數調用結束時不返回'this',或'_'或'cat',因爲它應該返回操作的值。我發現它創建了所有以編程方式進行編程的原型。 – ThomasReggi

+0

你將不得不將所有的方法複製到一個新的貓對象:S,也是結果 – xiumeteo

+0

每個下劃線函數似乎都不會複製任何東西只是[似乎返回結果](https://github.com/ jashkenas /下劃線/斑點/主/ underscore.js#L520-L522)。 – ThomasReggi

0

我抄出了所有可以鏈接的下劃線函數,並將其添加到對象的末尾。

這個想法是你可以創建類似於普通函數的函數,執行某種輸入/輸出操作。然後,您可以遍歷所有這些函數,並構建與創建對象鏈相關的原型,如存儲數據和傳輸參數。

var _ = require("underscore") 

var cat = function(obj) { 
    if (obj instanceof cat) return obj; 
    if (!(this instanceof cat)) return new cat(obj); 
    this._wrapped = obj; 
}; 

cat.eat = function(food){ 
    if(food == "tuna") return 95 
    if(food == "milk") return 35 
    return 0 
} 

cat.play = function(energy){ 
    if(energy < 50) return 0 
    return 100 
} 

// Add a "chain" function. Start chaining a wrapped Underscore object. 
cat.chain = function(obj) { 
    var instance = cat(obj); 
    instance._chain = true; 
    return instance; 
}; 

// Helper function to continue chaining intermediate results. 
var chainResult = function(instance, obj) { 
    return instance._chain ? cat(obj).chain() : obj; 
}; 

var ArrayProto = Array.prototype 
var push = ArrayProto.push 

cat.mixin = function(obj) { 
    _.each(_.functions(obj), function(name) { 
    var func = cat[name] = obj[name]; 
    cat.prototype[name] = function() { 
     var args = [this._wrapped]; 
     push.apply(args, arguments); 
     return chainResult(this, func.apply(cat, args)); 
    }; 
    }); 
}; 

// Add all of the Underscore functions to the wrapper object. 
cat.mixin(cat); 

// Extracts the result from a wrapped and chained object. 
cat.prototype.value = function() { 
    return this._wrapped; 
}; 


// var energy = cat.eat("tuna") 
// var status = cat.play(energy) 
// 
// console.log(status) // 100 

var status = cat.chain("tuna") 
    .eat() 
    .play() 
    .value() 

console.log(status) // 100 

UPDATE:

我發的功能,使任何對象可鏈接的對象下劃線混入。

這裏的混入:

var _ = require("underscore") 

_.mixin({ 
    prototypeChain: function(thObj){ 
    return function(obj) { 
     var instance = thObj(obj); 
     instance._chain = true; 
     return instance; 
    } 
    }, 
    prototypeExtend: function(theObj){ 
    var chainResult = function(instance, obj) { 
     return instance._chain ? theObj(obj).chain() : obj; 
    } 
    var prototypes = _.map(_.functions(theObj), function(name) { 
     var func = theObj[name]; 
     theObj.prototype[name] = function() { 
     var args = [this._wrapped]; 
     Array.prototype.push.apply(args, arguments); 
     return chainResult(this, func.apply(theObj, args)); 
     }; 
    }); 
    _.extend(theObj, prototypes) 
    }, 
    prototypeValue: function(){ 
    return function(){ 
     return this._wrapped; 
    } 
    } 
}) 

下面是它如何工作的:

var cat = function(obj) { 
    if (obj instanceof cat) return obj; 
    if (!(this instanceof cat)) return new cat(obj); 
    this._wrapped = obj; 
}; 

cat.eat = function(food){ 
    if(food == "tuna") return 95 
    if(food == "milk") return 35 
    return 0 
} 

cat.play = function(energy){ 
    if(energy < 50) return 0 
    return 100 
} 

cat.chain = _.prototypeChain(cat) 
_.prototypeExtend(cat) 
cat.prototype.value = _.prototypeValue() 

var energy = cat.eat("tuna") 
var status = cat.play(energy) 

console.log(status) // 100 

var status = cat.chain("tuna") 
    .eat() 
    .play() 
    .value() 

console.log(status) // 100