Можете ли вы изменить функцию Javascript после объявления?
Скажем, у меня есть var a = function() { return 1; }
. Можно ли изменить a
так, чтобы a()
возвращал 2
? Возможно, отредактировав свойство объекта a
, поскольку каждая функция является объектом?
Обновление: Ничего себе, спасибо за все ответы. Однако, боюсь, я не хотел просто переназначать переменную, но фактически редактировать существующую функцию. Я думаю о том, как вы можете объединить частичные функции в Scala, чтобы создать новый PartialFunction
. Я заинтересован в написании чего-то подобного в Javascript и думал, что существующая функция может быть обновлена, а не создавать совершенно новый объект Function
.
Ответы
Ответ 1
Вы можете делать всевозможные забавные вещи с помощью 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
Voila.
Изменить: обновлено, чтобы показать это в более сумасшедшем сценарии:
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
Вы можете видеть здесь, что, хотя сначала определяется "тест", и мы переопределяем подстроку(), это изменение все еще применяется.
Боковое замечание: вам действительно нужно пересмотреть свою архитектуру, если вы это делаете... вы собираетесь запутать дерьмо из какого-то плохого разработчика через 5 лет после того, как он/она посмотрит на определение функции, которое предположительно для возврата 1, но, кажется, всегда возвращает 2....
Ответ 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(), чтобы получить строку, содержащую объявление функции. Некоторые вызовы replace() для подготовки строки для использования с конструктором функций и для изменения источника функции.
Ответ 3
var a = function() { return 1; }
alert(a()) // 1
a = function() { return 2; }
alert(a()) // 2
технически вы теряете одно определение функции и заменяете его другим.
Ответ 4
Как об этом, без необходимости переопределять функцию:
var a = function() { return arguments.callee.value || 1; };
alert(a()); // => 1
a.value = 2;
alert(a()); // => 2
Ответ 5
Я придерживаюсь решения jvenema, в котором мне не нравится глобальная переменная "old". Кажется, лучше сохранить старую функцию внутри новой:
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
Ответ 6
Итак, вы хотите изменить код функции напрямую, на месте, а не просто переназначить другую функцию существующей переменной.
Мне очень жаль это говорить, но насколько я мог это понять, и я попытался - это невозможно. Правда, функция является объектом, и как таковая она имеет методы и свойства, которые могут быть изменены и перезаписаны на самом объекте. К сожалению, тело функции не является одним из них. Он не присваивается публичному имуществу.
В документации в MDN перечислены свойства и методы объекта функции. Ни один из них не дает нам возможности манипулировать телом функции снаружи.
Что, поскольку согласно спецификации, тело функции хранится во внутреннем [[Code]]
свойстве объекта функции, который не может доступ к ним осуществляется напрямую.
Ответ 7
Все возможные решения придерживаются подхода "обертывания функций".
Самый надежный среди них, похоже, один из rplantiko.
Такая аппаратная упаковка легко может быть абстрагирована. Концепция/шаблон
его можно назвать "Модификацией метода". Его реализация определенно
принадлежит 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());
Ответ 8
Если вы отлаживаете javascript и хотите увидеть, как изменения кода влияют на страницу, вы можете использовать это расширение Firefox для просмотра/изменения javascripts:
Выполнить расширение JS Firefox:
https://addons.mozilla.org/en-US/firefox/addon/1729
Ответ 9
Совершенно верно. Просто назначьте ему новую функцию.
Ответ 10
Можете ли вы не просто определить его позже? Когда вы хотите изменить, попробуйте просто переопределить его как:
a = function() { return 2; }
Ответ 11
Это Очистить пример на основе элемента управления timepicker eworld.ui
www.eworldui.net
Имея TimePicker eworld.ui
, где JavaScript недоступен извне, вы не можете найти js, связанный с этими элементами управления. Итак, как вы можете добавить событие onchange к timepicker?
Существует функция js
, вызываемая при Select
времени между всеми параметрами, которые предлагает вам элемент управления. Эта функция: 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 = function (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 ( 'видимого'); if (customFunc!= ") eval (customFunc +" (' "+ selTime +" ', ' "+ tbName +" '); "); eval (postbackFunc +" ();");
>>>>>>> My function >>>>> RaiseChange(tbName);
}
Я добавил функцию "Моя функция" в функцию, поэтому теперь я могу имитировать событие onchange, когда я выбираю время.
RaiseChange (...) может быть любым, что вы хотите.
Ответ 12
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);
Попробуйте этот. Он изменит исходную функцию на новый код, используя обратный вызов для проверки каждой строки кода.