And*_*kin 101 javascript function
什么是在JavaScript中克隆函数的最快方法(有或没有它的属性)?
我想到的两个选择是eval(func.toString())
和function() { return func.apply(..) }
.但我担心eval的性能和包装将使堆栈变得更糟,如果应用很多或应用于已经包装,可能会降低性能.
new Function(args, body)
看起来不错,但是如何在JS中没有JS解析器的情况下可靠地将现有函数拆分为args和body?
提前致谢.
更新: 我的意思是能够做到
var funcB = funcA.clone(); // where clone() is my extension
funcB.newField = {...}; // without affecting funcA
Run Code Online (Sandbox Code Playgroud)
Pic*_*tor 96
这是一个更新的答案
var newFunc = oldFunc.bind({}); //clones the function with '{}' acting as it's new 'this' parameter
Run Code Online (Sandbox Code Playgroud)
但是".bind"是JavaScript的现代(> = iE9)功能(具有MDN兼容性解决方案)
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
注意:它不会克隆功能对象的附加连接特性,包括在原型属性.感谢@jchook
注意:新函数这个变量与bind()上给出的参数一致,即使在新函数apply()调用上也是如此.感谢@Kevin
function oldFunc() { console.log(this.msg); }
var newFunc = oldFunc.bind( { msg:"You shall not pass!" } ); // this object is binded
newFunc.apply( { msg:"hello world" } ); //logs "You shall not pass!" instead
Run Code Online (Sandbox Code Playgroud)
注意:绑定的函数对象,instanceof将newFunc/oldFunc视为相同.感谢@Christopher
(new newFunc()) instanceof oldFunc; //gives true
(new oldFunc()) instanceof newFunc; //gives true as well
newFunc == oldFunc; //gives false however
Run Code Online (Sandbox Code Playgroud)
Jar*_*red 51
试试这个:
var x = function() {
return 1;
};
var t = function(a,b,c) {
return a+b+c;
};
Function.prototype.clone = function() {
var that = this;
var temp = function temporary() { return that.apply(this, arguments); };
for(var key in this) {
if (this.hasOwnProperty(key)) {
temp[key] = this[key];
}
}
return temp;
};
alert(x === x.clone());
alert(x() === x.clone()());
alert(t === t.clone());
alert(t(1,1,1) === t.clone()(1,1,1));
alert(t.clone()(1,1,1));
Run Code Online (Sandbox Code Playgroud)
Jus*_*tin 18
这是Jared答案的稍微好一点的版本.克隆的次数越多,嵌套函数就越深.它总是称为原件.
Function.prototype.clone = function() {
var cloneObj = this;
if(this.__isClone) {
cloneObj = this.__clonedFrom;
}
var temp = function() { return cloneObj.apply(this, arguments); };
for(var key in this) {
temp[key] = this[key];
}
temp.__isClone = true;
temp.__clonedFrom = cloneObj;
return temp;
};
Run Code Online (Sandbox Code Playgroud)
另外,为了响应pico.creator给出的更新答案,值得注意的是,bind()
Javascript 1.8.5中添加的函数与Jared的答案具有相同的问题 - 它将保持嵌套,每次使用时都会导致函数变慢.
由于好奇但仍无法找到上述问题的性能主题的答案,我为nodejs 编写了这个要点,以测试所有呈现(和评分)解决方案的性能和可靠性.
我已经比较了克隆函数创建和克隆执行的挂壁时间.结果与断言错误一起包含在要点的注释中.
再加上我的两分钱(基于作者的建议):
clone0分(更快但更丑):
Function.prototype.clone = function() {
var newfun;
eval('newfun=' + this.toString());
for (var key in this)
newfun[key] = this[key];
return newfun;
};
Run Code Online (Sandbox Code Playgroud)
clone4 cent(较慢但对于那些不喜欢eval()的人来说只为他们和他们的祖先所知的目的):
Function.prototype.clone = function() {
var newfun = new Function('return ' + this.toString())();
for (var key in this)
newfun[key] = this[key];
return newfun;
};
Run Code Online (Sandbox Code Playgroud)
至于性能,如果eval/new函数比包装器解决方案慢(并且它实际上取决于函数体大小),它会为您提供裸函数克隆(我的意思是具有属性但非共享状态的真正浅层克隆)没有不必要的模糊隐藏属性,包装函数和堆栈问题.
此外,总有一个重要因素需要考虑:代码越少,错误的地方就越少.
使用eval/new函数的缺点是克隆和原始函数将在不同的范围内运行.它不适用于使用范围变量的函数.使用类似绑定的包装的解决方案与范围无关.
让这个方法起作用非常令人兴奋,所以它使用Function调用来复制一个函数.
关于MDN功能参考中描述的闭包的一些限制
function cloneFunc( func ) {
var reFn = /^function\s*([^\s(]*)\s*\(([^)]*)\)[^{]*\{([^]*)\}$/gi
, s = func.toString().replace(/^\s|\s$/g, '')
, m = reFn.exec(s);
if (!m || !m.length) return;
var conf = {
name : m[1] || '',
args : m[2].replace(/\s+/g,'').split(','),
body : m[3] || ''
}
var clone = Function.prototype.constructor.apply(this, [].concat(conf.args, conf.body));
return clone;
}
Run Code Online (Sandbox Code Playgroud)
请享用.
简短而简单:
Function.prototype.clone = function() {
return new Function('return ' + this.toString())();
};
Run Code Online (Sandbox Code Playgroud)
const oldFunction = params => {
// do something
};
const clonedFunction = (...args) => oldFunction(...args);
Run Code Online (Sandbox Code Playgroud)