是否可以重写JavaScript的apply函数?
Is it possible to rewrite JavaScript's apply function?
我一直在重写很多 JavaScript 的高阶函数以掌握函数式编程的窍门,但我坚持 apply
。在JavaScript中可以写apply
吗?假设所有其他本机函数都存在,并且正在使用 ES5 规范。
对于 ES5 及更低版本,我认为不使用 eval
就无法做到(见下文)。你可以 almost 在 args.length
上使用 massive switch 语句来做到这一点,但在某些时候,你只需要说有一个限制到 switch
.
中 cases
的数量
Function.prototype.newApply = function(thisArg, args) {
switch (args.length) {
case 0: return this.call(thisArg);
case 1: return this.call(thisArg, args[0]);
case 2: return this.call(thisArg, args[0], args[1]);
// etc..
default: throw new Error("She canna tek any more!");
}
};
不过,如果您允许 eval
,您绝对可以做到 — 完全归功于 blex 建议 eval
:
Function.prototype.newApply = function(thisArg, args) {
var f = this,
call = "f.call(thisArg",
i;
for (i = 1; i < args.length; ++i) {
call += ", args[" + i + "]";
}
call += ")";
return eval(call);
};
实例:
Function.prototype.newApply = function(thisArg, args) {
var f = this,
call = "f.call(thisArg",
i;
for (i = 0; i < args.length; ++i) {
call += ", args[" + i + "]";
}
call += ")";
return eval(call);
};
var obj1 = {
foo: "foo",
bar: "bar"
};
var obj2 = {
foo: "F",
bar: "B"
};
function caps(o1, o2) {
var k;
snippet.log("this.x = " + this.x);
for (k in o1) {
o1[k] = o1[k].toUpperCase();
}
for (k in o2) {
o2[k] = o2[k].toLowerCase();
}
}
caps.newApply({x:42}, [obj1, obj2]);
snippet.log(JSON.stringify(obj1));
snippet.log(JSON.stringify(obj2));
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
或者如果你想使用 Array#reduce
:
Function.prototype.newApply = function(thisArg, args) {
var f = this,
call = args.reduce(function(acc, _, index) {
return acc + ", args[" + index + "]";
}, "f.call(thisArg") + ")";
return eval(call);
};
你在问题中提到了 ES5,但只是为了完整起见:由于扩展运算符 (...
),在 ES6 中它真的很简单 (...
):
Function.prototype.newApply = function(thisArg, args) {
return this.call(thisArg, ...args);
};
我一直在重写很多 JavaScript 的高阶函数以掌握函数式编程的窍门,但我坚持 apply
。在JavaScript中可以写apply
吗?假设所有其他本机函数都存在,并且正在使用 ES5 规范。
对于 ES5 及更低版本,我认为不使用 eval
就无法做到(见下文)。你可以 almost 在 args.length
上使用 massive switch 语句来做到这一点,但在某些时候,你只需要说有一个限制到 switch
.
cases
的数量
Function.prototype.newApply = function(thisArg, args) {
switch (args.length) {
case 0: return this.call(thisArg);
case 1: return this.call(thisArg, args[0]);
case 2: return this.call(thisArg, args[0], args[1]);
// etc..
default: throw new Error("She canna tek any more!");
}
};
不过,如果您允许 eval
,您绝对可以做到 — 完全归功于 blex 建议 eval
:
Function.prototype.newApply = function(thisArg, args) {
var f = this,
call = "f.call(thisArg",
i;
for (i = 1; i < args.length; ++i) {
call += ", args[" + i + "]";
}
call += ")";
return eval(call);
};
实例:
Function.prototype.newApply = function(thisArg, args) {
var f = this,
call = "f.call(thisArg",
i;
for (i = 0; i < args.length; ++i) {
call += ", args[" + i + "]";
}
call += ")";
return eval(call);
};
var obj1 = {
foo: "foo",
bar: "bar"
};
var obj2 = {
foo: "F",
bar: "B"
};
function caps(o1, o2) {
var k;
snippet.log("this.x = " + this.x);
for (k in o1) {
o1[k] = o1[k].toUpperCase();
}
for (k in o2) {
o2[k] = o2[k].toLowerCase();
}
}
caps.newApply({x:42}, [obj1, obj2]);
snippet.log(JSON.stringify(obj1));
snippet.log(JSON.stringify(obj2));
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
或者如果你想使用 Array#reduce
:
Function.prototype.newApply = function(thisArg, args) {
var f = this,
call = args.reduce(function(acc, _, index) {
return acc + ", args[" + index + "]";
}, "f.call(thisArg") + ")";
return eval(call);
};
你在问题中提到了 ES5,但只是为了完整起见:由于扩展运算符 (...
),在 ES6 中它真的很简单 (...
):
Function.prototype.newApply = function(thisArg, args) {
return this.call(thisArg, ...args);
};