"добавить", которая работает с различными комбинациями цепочек/аргументов
Я пытаюсь написать функцию добавления, которая будет работать во многих сценариях.
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());
Ответы
Ответ 1
Посмотрев на то, как вы используете arguments
аналогичным образом в двух разных местах, ясно, что вы дублируете функциональность, и именно поэтому вы сталкиваетесь с этой проблемой с необходимостью "бесконечно гнездовать" .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>
Ответ 2
Так как вы возвращаете сумму в функции 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
Также им нужно всегда возвращать ints (не строки), и кажется, что иногда они делают, а в других случаях они этого не делают?
Да, это определенно концептуальная проблема. Эти две вещи, которые вы хотите, несовместимы. Является ли 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));
}
Ответ 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;
}
JS-Fiddle