编写一个函数来设置另一个函数中的一些但不一定是所有参数

Writing a function to set some but not necessarily all parameters in another function

我有一个编码面试测试,问了以下我无法完全解决的问题。我想知道按照我的方法执行此操作的最佳方法 - 也很抱歉这很长。

你得到了一个像这样读入的函数(不一定是 2 个参数):

function add(a, b) {
    return a + b;
}

objective 是创建一个函数来初始化其中一些变量,然后再次调用该函数来执行计算,如 function setParam(func, params)。要使用它,您需要执行以下操作:

_add = setParam(add, {b:9})
_add(10) // should return 19

我的解决方案是解析函数以查看有多少参数,然后使用给定的参数设置它们,但由于我几乎不知道 javascript 我从来没有能够真正 return 一个函数仅设置了一些变量,其他变量仍未定义。

(尝试解决)

function  setParam(func, params) {

// varray is an array of the the varriables from the function, func
// ie varray = [a,b] in this test
var varray = /function[^\(]*\(([^\)]*)\)/.exec(func.toString())[1].split(',');

//creates an array, paramset, that has the variables in func defined  
//where possible
// ex paramset = [a,9] if only b was set

var paramsset = []
for (i = 0; i < varray.length; i++) { 
    if (typeof(params[varray[i]]) == "undefined"){
        paramsset[i] = varray[i];
    } else {
        paramsset[i] = params[varray[i]];
    }
}
//////

// need to modify existing function and return with added parameters
// where I'm stuck as this doesn't work.
newfunc = (function(){
    var _func = func;
    return function() {
        return _func.apply(this, paramsset);
    }
})();
newfunc()

}

我确定我这样做的方式不正确,但我们将不胜感激。

我猜他们可能一直在测试偏应用的知识。 (不是 currying

编辑:根据您的评论进行了编辑。这是 Crockford 的 curry 函数,直接来自他的书。

function add(a, b) {
  return a + b;
}

if (!Function.prototype.partial) { 
    Function.prototype.partial = function() { 
        var slice = Array.prototype.slice, 
            args = new Array(arguments.length), 
            that = this;
        for (var i = 0; i < args.length; i++) { 
            args[i] = arguments[i]; 
        } 
        return function() { 
            return that.apply(null, args.concat(slice.apply(arguments))); 
        }
    }; 
}

var example = add.partial(4);
console.log(example(10)); // output 14
console.log(example(20)); // output 24 

var example = adder(4)example 指定为带有 a 闭包的函数(在本例中为 4)。当像 console.log 中那样调用 example 时,它实际上会返回 "the value of a when example was assigned, plus this new number."

partial() 函数演练:

  1. 将参数转换为数组
  2. returns 一个函数被传递了给定的参数,以后可以调用它。它有一个带有先前分配的参数的闭包。

我当然不是在提倡采用该解决方案,但我仍然实现了一些东西来遵循您最初的 API 设计,只是为了好玩。 signatures 弱映射是必要的,以便保留初始函数的签名,以便我们可以在部分应用的函数上再次调用 setParams

var setParams = (function () {
    var signatures = new WeakMap();
    
    return function (fn, paramsToApply) {
        var signature = signatureOf(fn), newFn;
        
        validateParams(paramsToApply, signature.params);
        
        newFn = function () {
            var params = appliedParamsFrom(arguments, paramsToApply, signature.indexes);
            
            return fn.apply(this, params);
        };
        
        signatures.set(newFn, signature);
        
        return newFn;
    };
    
    function signatureOf(fn) {
        return signatures.has(fn)? 
            signatures.get(fn) :
            parseSignatureOf(fn);
    }
    
    function parseSignatureOf(fn) {
        return String(fn)
            .match(/function.*?\((.*?)\)/)[1]
            .replace(/\s+/g, '')
            .split(',')
            .reduce(function (r, param, index) {
                r.indexes[param] = index;
                r.params.push(param);
                return r;
            }, { indexes: {}, params: [] });
    }
    
    function validateParams(paramsToApply, actualParams) {
        Object.keys(paramsToApply).forEach(function (param) {
            if (actualParams.indexOf(param) == -1) throw new Error("parameter '" + param + "' could not be found in the function's signature which is: 'function (" + actualParams + ")'");
        });
    }
    
    function appliedParamsFrom(args, paramsToApply, paramsIndex) {
        var appliedParams = [],
            usedIndexes = [],
            argsIndex = 0, 
            argsLen = args.length,
            argSpotIndex = 0;
      
        
        Object.keys(paramsToApply).forEach(function (param) {
            var index = paramsIndex[param];
          
            appliedParams[index] = paramsToApply[param];
          
            usedIndexes.push(index);
        });
      
        while (argsIndex < argsLen) {
            if (usedIndexes.indexOf(argSpotIndex) == -1) {
                appliedParams[argSpotIndex] = args[argsIndex++];
            }
          
            ++argSpotIndex;
        }
        
        return appliedParams;
    }
})();


function add(a, b) { return a + b; }

var addTo9 = setParams(add, { b: 9 });
var add10To9 = setParams(addTo9, { a: 10 });

document.write(addTo9(10) + ', ' + add10To9());

现在,请注意 JavaScript 带有 Function.prototype.bind 函数,该函数允许按顺序执行部分函数应用程序。 bind 的第一个参数与参数无关,它是绑定 this 值。

function add(a, b) { return a + b; }

var addTo9 = add.bind(null, 9);

document.write(addTo9(10));

最后,如果您需要的话,还有一个带有标示符的实现:

var partial = (function (undefined) {
  var PLACEHOLDER = {};
  
  function partial(fn, partialArgs) {
    return function () {
      return fn.apply(this, applyPartialArgs(arguments, partialArgs));
    };
  }
  
  Object.defineProperty(partial, 'PLACEHOLDER', {
    get: function () { return PLACEHOLDER; }
  });
  
  return partial;
  
  function applyPartialArgs(args, partialArgs) {
    var appliedArgs = partialArgs.map(function (arg) {
          return arg === PLACEHOLDER? undefined : arg;
        }),
        partialArgsLen = partialArgs.length,
        argsLen = args.length,
        argsIndex = 0,
        argSpotIndex = 0;
    
    while (argsIndex < argsLen) {
      if (
        partialArgs[argSpotIndex] === PLACEHOLDER ||
        argSpotIndex >= partialArgsLen
      ) {
        appliedArgs[argSpotIndex] = args[argsIndex++];
      }
      
      ++argSpotIndex;
    }
    
    return appliedArgs;
  }

})();

function add(a, b, c, d) {
  return a + b + c + d;
}

var _ = partial.PLACEHOLDER;

var addTo9 = partial(add, [_, 5, _, 4]);

document.write(addTo9(5, 5));