我正在尝试编写一个可在许多场景下工作的添加功能。
add(2,2,2) //6
add(2,2,2,2) //8
add(2)(2)(2) // 6
add(2)(2)(2,2).value() //8
add(2,2)(2) + 2 //8
add(2).add(2) //4
add(2,2,2).add(2).add(2,2).value() //12
add(2,2,2).add(2).value() //8
这是我到目前为止所做的:
function add(){
var sum = 0;
for( var i in arguments ){
sum += arguments[i];
}
var ret = add.bind(null, sum);
ret.value = function () {
return sum;
}
ret.add = function () {
for( var i in arguments ){
sum += arguments[i];
}
return sum;
}
ret.valueOf = function(){ return sum; };
return ret;
}
console.log(add(2,2,2));
console.log(add(2,2,2,2));
console.log(add(2)(2)(2));
console.log(add(2)(2)(2,2).value());
console.log(add(2,2)(2) + 2);
console.log(add(2).add(2));
console.log(add(2,2,2).add(2).value());
console.log(add(2,2,2).add(2).add(2,2).value());
我遇到过最后两种情况的问题:
add(2,2,2).add(2).add(2,2).value() //12
add(2,2,2).add(2).value() //8
似乎我必须继续嵌套添加函数,如果我想将两个以上链接在一起并且还为每个函数添加值函数,但显然我遗漏了一些简单的东西,这将允许我链接它们尽我所能,并且对其中任何一个都有价值。
此外,他们需要始终返回整数(而不是字符串),似乎有时他们会这样做,有时他们不这样做?
答案 0 :(得分:16)
看看你在两个不同的地方以类似的方式使用arguments
的方式,很明显你正在复制功能,这就是为什么你必须“无限地嵌套”{ {1}}方法。
要认识到的关键是.value()
可以返回一个将自身引用为自己的add()
属性的函数。这将使add
的行为与add(1,2)(3)
完全相同。这可以这样做:
add(1,2).add(3)
function add() {
var sum = Array.prototype.reduce.call(arguments, function(l, r) {
return l + r;
}, 0);
var ret = add.bind(null, sum);
ret.add = ret;
ret.value = ret.valueOf = Number.prototype.valueOf.bind(sum);
ret.toString = Number.prototype.toString.bind(sum);
return ret;
}
snippet.log(add(2,2,2));
snippet.log(add(2,2,2,2));
snippet.log(add(2)(2)(2));
snippet.log(add(2)(2)(2,2).value());
snippet.log(add(2,2)(2) + 2);
snippet.log(add(2).add(2));
snippet.log(add(2,2,2).add(2).value());
snippet.log(add(2,2,2).add(2).add(2,2).value());
snippet.log(add(1, 2, 3)(4, 5).add(6, 7)(8).add(9, 10));
snippet.log(add(5,4)(3).add(2)(1) * 10);
上述方法仍存在两个潜在问题,一个是次要问题,另一个是次要问题:
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
函数时(包括链接期间)都会重新执行属性引用和函数定义add
标识符,则会导致整个实现中断:
add
这两种方法都可以通过IIFE来解决:
function add() {
var sum = Array.prototype.reduce.call(arguments, function(l, r) {
return l + r;
}, 0);
var ret = add.bind(null, sum);
ret.add = ret;
ret.value = ret.valueOf = Number.prototype.valueOf.bind(sum);
ret.toString = Number.prototype.toString.bind(sum);
return ret;
}
var myAdd = add;
add = "boom!";
myAdd(1, 2, 3); // TypeError: add.bind is not a function
var add = (function () {
var reduce = Array.prototype.reduce,
np = Number.prototype,
valueOf = np.valueOf,
toString = np.toString,
plus = function (l, r) { return l + r; };
return function add() {
var sum = reduce.call(arguments, plus, 0);
var ret = add.bind(null, sum);
ret.add = ret;
ret.value = ret.valueOf = valueOf.bind(sum);
ret.toString = toString.bind(sum);
return ret;
}
})();
var myAdd = add;
add = "U Can't Touch This"; // hammertime
snippet.log(myAdd(1, 2, 3)(4, 5).add(6, 7)(8).add(9, 10));
snippet.log(myAdd(5,4)(3).add(2)(1) * 10);
答案 1 :(得分:4)
我尝试使用this
进行即兴创作。适用于所有情况。
function add(){
var sum = this instanceof Number?this: 0;
for( var i in arguments ){
sum += arguments[i];
}
var ret = add.bind(sum);
ret.add = ret;
ret.value = ret.valueOf = function() { return sum; };
ret.toString = sum.toString.bind(sum);
return ret;
}
答案 2 :(得分:3)
因为你在ret.add函数中返回总和,这就是为什么错误即将来临尝试这样的事情,希望它能解决你的问题
function add(){
var sum = 0;
for( var i in arguments ){
sum += arguments[i];
}
var ret = add.bind(null, sum);
ret.value = function () {
return sum;
}
ret.add = function () {
for( var i in arguments ){
sum += arguments[i];
}
return ret;
}
ret.valueOf = function(){ return sum; };
return ret;
}
答案 3 :(得分:3)
此外,他们需要始终返回整数(而不是字符串),似乎有时他们会这样做,有时他们不这样做?
是的,这绝对是一个概念问题。你想要的这两件事是不兼容的。 add(2,2,2)
是add
方法的数字或其他内容吗?
add(2,2,2) //6
add(2,2,2).add(2).value() //8
即使有一种奇特的方法来向nubmers添加方法,我强烈建议保持简单并始终需要“.value()”调用来结束链。这样所有对“.add”的调用都会返回一个“加法器对象”,所有对“.value”的调用都会返回一个常规数字。
似乎我必须继续嵌套添加函数,如果我想将两个以上链接在一起并且还为每个函数添加值函数,但显然我缺少一些简单的东西,这将允许我链接它们尽我所能,并且对其中任何一个都有价值。
答案是使用递归函数。这是一个创建我之前提到的“加法器”对象的函数:
function sumArray(arr){
var s = 0;
for(var i=0; i<arr.length; i++){
s += arr[i];
}
return s;
}
function mkAdder(currSum){
return {
value: function(){
return currSum;
},
valueOf: function(){
return currSum;
},
add: function(/**/){
return mkAdder(currSum + sumArray(arguments));
}
}
}
然后你的初始添加功能将如下所示:
function add(/**/){
return mkAdder(sumArray(arguments));
}