你可以在声明后改变一个Javascript函数吗?
假设我有var a = function() { return 1; }
var a = function() { return 1; }
。 是否有可能改变a
以便a()
返回2
? 也许通过编辑一个对象的属性,因为每个函数都是一个对象 ?
更新:哇,谢谢所有的答复。 但是,恐怕我不想简单地重新分配variables,而是实际编辑现有的函数。 我正在思考如何在Scala中组合部分函数来创build一个新的PartialFunction
。 我有兴趣在JavaScript中写类似的东西,并认为现有的函数可能会被更新,而不是创build一个全新的Function
对象。
你可以使用JavaScript做各种有趣的东西,包括重新定义函数:
var a = function(){ return 1; } alert(a()); //1 // keep a reference var old = a; // redefine a = function(){ // call the original function with any arguments specified, storing the result var originalResult = old.apply(old, arguments); // add one return originalResult + 1; }; alert(a()); //2
瞧。
编辑:更新以显示在一个更疯狂的情况下:
var test = new String("123"); console.log(test.toString()); // logs 123 console.log(test.substring(0)); // logs 123 String.prototype.substring = function(){ return "hahanope"; } console.log(test.substring(0)); // logs hahanope
你可以在这里看到,即使先定义了“test”,然后我们重新定义了substring(),但这个改变仍然适用。
注意:如果你这样做的话,你真的应该重新考虑你的架构……当他/她正在查看一个应该返回1的函数定义时,你会在5年的时间里把一些糟糕的开发者弄糊涂了,但似乎总是返回2 ….
我用这样的东西来修改一个现有的函数,这个函数声明对我来说是不可访问的:
// declare function foo var foo = function (a) { alert(a); }; // modify function foo foo = new Function ( "a", foo.toSource() .replace("alert(a)", "alert('function modified - ' + a)") .replace(/^function[^{]+{/i,"") // remove everything up to and including the first curly bracket .replace(/}[^}]*$/i, "") // remove last curly bracket and everything after<br> );
而不是toSource(),你可以使用toString()来获取一个包含函数声明的string。 一些调用replace()来准备用于函数构造函数的string并修改函数的源代码。
var a = function() { return 1; } alert(a()) // 1 a = function() { return 2; } alert(a()) // 2
从技术上讲,你正在失去一个函数定义,并用另一个函数定义。
如何呢,而不必重新定义的function:
var a = function() { return arguments.callee.value || 1; }; alert(a()); // => 1 a.value = 2; alert(a()); // => 2
我坚持jvenema的解决scheme,我不喜欢全局variables“老”。 旧的function保留在新的function中似乎更好:
function a() { return 1; } // redefine a = (function(){ var _a = a; return function() { // You may reuse the original function ... // Typical case: Conditionally use old/new behaviour var originalResult = _a.apply(this, arguments); // ... and modify the logic in any way return originalResult + 1; } })(); a() // --> gives 2
所以你想要直接修改一个函数的代码,而不是仅仅为一个已经存在的variables重新分配一个不同的函数。
我讨厌这样说,但据我所知,我已经尝试过了,这是不可能的。 诚然,函数是一个对象,因此它具有可以在对象本身上进行调整和覆盖的方法和属性。 不幸的是,函数体不是其中之一。 它没有被分配到公共财产。
MDN上的文档列出了函数对象的属性和方法。 他们都没有给我们机会从外面操纵职能机构。
这是因为根据规范 ,函数体存储在函数对象的内部[[Code]]
属性中,不能直接访问。
所有可行的解决scheme都坚持“function包装法”。 其中最可靠的似乎是rplantiko之一 。
这样的function包装很容易被抽象掉。 概念/模式本身可以被称为“方法修改”。 它的实现绝对属于Function.prototype
。 标准的原型方法修饰符如before
, after
, around
, afterThrowing
以及afterFinally
。
至于rplantiko的上述例子…
function a () { return 1; } // redefine a = (function () { var _a = a; return function () { // You may reuse the original function ... // Typical case: Conditionally use old/new behaviour var originalResult = _a.apply(this, arguments); // ... and modify the logic in any way return originalResult + 1; }; })(); a(); // --> gives 2
…使用[around]
,代码将转换为…
function a () { return 1; } console.log("a : ", a); console.log("a() : ", a()); a = a.around(function (proceed, interceptor, args) { return (proceed() + 1); }); console.log("a : ", a); console.log("a() : ", a());
如果您正在debuggingJavaScript,并希望查看代码的更改如何影响页面,则可以使用此Firefox扩展来查看/更改javascripts:
执行JS firefox扩展: https : //addons.mozilla.org/en-US/firefox/addon/1729
你能不能以后再定义它? 当你想改变尝试只是重新定义它:
a = function() { return 2; }
绝对。 只需分配给它一个新的function。
这是一个基于控制时间eworld.ui
eworld.ui http://www.eworldui.net的;eworld.ui
示例
有一个TimePicker eworld.ui
,其中JavaScript是从外面无法访问,您不能find任何与这些控件相关的js。 那么如何添加一个onchange事件到timepicker?
当您Select
控件提供给您的所有选项之间的时间时,会调用一个js
函数。 这个function是: TimePicker_Up_SelectTime
首先你必须复制这个函数里面的代码。
评估… quikwatch … TimePicker_Up_SelectTime.toString()
function TimePicker_Up_SelectTime(tbName, lblName, divName, selTime, enableHide, postbackFunc, customFunc) { document.getElementById(tbName).value = selTime; if(lblName != '') document.getElementById(lblName).innerHTML = selTime; document.getElementById(divName).style.visibility = 'hidden'; if(enableHide) TimePicker_Up_ShowHideDDL('visible'); if(customFunc != "") eval(customFunc + "('" + selTime + "', '" + tbName + "');"); eval(postbackFunc + "();");
}
现在
使用之前保存的代码重新分配相同的源代码,但添加任何你想要的。
TimePicker_Up_SelectTime =函数(tbName,lblName,divName,selTime,enableHide,postbackFunc,customFunc){document.getElementById(tbName).value = selTime; if(lblName!='')document.getElementById(lblName).innerHTML = selTime; document.getElementById(divName).style.visibility ='hidden'; if(enableHide)TimePicker_Up_ShowHideDDL('visible'); if(customFunc!=“”)eval(customFunc +“('”+ selTime +“','”+ tbName +“');”); eval(postbackFunc +“();”);
>>>>>>> My function >>>>> RaiseChange(tbName); }
我已经添加了我的function,所以现在我可以模拟一个onchange事件,当我select一个时间。
RaiseChange(…)可以是任何你想要的。
function get_func(func) {//from StackOverflow //var args = Array.prototype.slice.call(arguments); var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; var ARGUMENT_NAMES = /([^\s,]+)/g; var fnStr = func.toString().replace(STRIP_COMMENTS, ''); var args = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')).match(ARGUMENT_NAMES); //var code = func.toString().match(/function[^{]+\{([\s\S]*)\}$/)[1]; var code =fnStr.slice(fnStr.indexOf("{") + 1, fnStr.lastIndexOf("}")); var func_full_name=fnStr.substr(0, fnStr.indexOf('{') ); var func_name=fnStr.slice(9, fnStr.indexOf('(')); if(args === null){ args = []; } return { func_name:func_name,func_full_name:func_full_name, code:code, args:args}; } function str_trim(str){ //replaces multi-line characters return str.replace(/\n/g,'').replace(/^ +| +$/gm, '').trim(); } function edit_func(func,callback){ var a_func=get_func(func); var lines = a_func.code.split('\n'); var output=[]; for(var i=0;i<lines.length;i++){ var code=str_trim(lines[i]); if(code!=''){ code =callback(code,output.length,a_func.args); output.push(code); } } //var test=Function(['a','b'],'alert(a);alert(b);'); //test(1,2); //func=Function(a_func.args,output.join('\n')); //return func; var head = document.getElementsByTagName('head')[0]; var script = document.createElement('script'); script.type = 'text/javascript'; script.text =a_func.func_full_name+'{'+ output.join('\n') + '}' ; head.appendChild(script); } function test(id) { var x, y; x = 5; y = 10; alert(x + y); alert(id); } edit_func(test,function(code,line,args){ if(line==3){ return 'alert(x*y);'; } return code; }); test(3);
试试这一个它会改变原来的function,使用一个新的代码检查每一行代码的callback。