编写一个函数来设置另一个函数中的一些但不一定是所有参数
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()
函数演练:
- 将参数转换为数组
- 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));
我有一个编码面试测试,问了以下我无法完全解决的问题。我想知道按照我的方法执行此操作的最佳方法 - 也很抱歉这很长。
你得到了一个像这样读入的函数(不一定是 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()
函数演练:
- 将参数转换为数组
- 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));