Добавление кода в функцию javascript программно
Я пытаюсь настроить существующую библиотеку JS без изменения исходного кода JS. Этот код загружает в несколько внешних файлов JS, к которым у меня есть доступ, и я хотел бы изменить одну из функций, содержащихся в исходном файле, без копирования и вставки всего этого во второй файл JS.
Так, например, в JS для запретов может быть такая функция:
var someFunction = function(){
alert("done");
}
Я хотел бы иметь возможность каким-то образом добавить или добавить некоторый код JS в эту функцию. Причина в первую очередь в том, что в исходном неприкасаемом JS функция довольно огромна, и если этот JS когда-либо будет обновлен, функция, с которой я перезаписываю его, будет устаревшей.
Я не совсем уверен, что это возможно, но я решил проверить.
5 ответов
Если someFunction
доступен в глобальном масштабе, тогда вы можете кэшировать функцию, создать свою собственную и заставить свою вызывать ее.
Так что, если это оригинал...
someFunction = function() {
alert("done");
}
Ты бы сделал это...
someFunction = (function() {
var cached_function = someFunction;
return function() {
// your code
var result = cached_function.apply(this, arguments); // use .apply() to call it
// more of your code
return result;
};
})();
Обратите внимание, что я использую .apply
вызвать кешированную функцию. Это позволяет мне сохранить ожидаемое значение this
и передайте любые аргументы, переданные в качестве отдельных аргументов, независимо от того, сколько их было.
Сначала сохраните фактическую функцию в переменной.
var oldFunction = someFunction;
затем определите свое собственное:
someFunction = function(){
// do something before
oldFunction();
// do something after
};
Вы можете создать функцию, которая вызывает ваш код, а затем вызывает функцию.
var old_someFunction = someFunction;
someFunction = function(){
alert('Hello');
old_someFunction();
alert('Goodbye');
}
Я не знаю, можете ли вы обновить функцию, но в зависимости от того, как на нее ссылаются, вы можете сделать новую функцию на ее месте:
var the_old_function = someFunction;
someFunction = function () {
/* ..My new code... */
the_old_function();
/* ..More of my new code.. */
}
Также. Если вы хотите изменить локальный контекст, вам нужно воссоздать функцию. Например:
var t = function() {
var a = 1;
};
var z = function() {
console.log(a);
};
Сейчас
z() // => log: undefined
затем
var ts = t.toString(),
zs = z.toString();
ts = ts.slice(ts.indexOf("{") + 1, ts.lastIndexOf("}"));
zs = zs.slice(zs.indexOf("{") + 1, zs.lastIndexOf("}"));
var z = new Function(ts + "\n" + zs);
А также
z() // => log: 1
Но это только самый простой пример. Для обработки аргументов, комментариев и возвращаемого значения потребуется еще много работы. Кроме того, есть еще много подводных камней.
toString | ломтик | indexOf | lastIndexOf | новая функция
Шаблон прокси (используемый user1106925) может быть помещен в функцию. Тот, который я написал ниже, работает с функциями, которые не входят в глобальную область, и даже с прототипами. Вы бы использовали это так:
extender(
objectContainingFunction,
nameOfFunctionToExtend,
parameterlessFunctionOfCodeToPrepend,
parameterlessFunctionOfCodeToAppend
)
В приведенном ниже фрагменте вы можете видеть, как я использую функцию для расширения test.prototype.doIt().
// allows you to prepend or append code to an existing function
function extender (container, funcName, prepend, append) {
(function() {
let proxied = container[funcName];
container[funcName] = function() {
if (prepend) prepend.apply( this );
let result = proxied.apply( this, arguments );
if (append) append.apply( this );
return result;
};
})();
}
// class we're going to want to test our extender on
class test {
constructor() {
this.x = 'instance val';
}
doIt (message) {
console.log(`logged: ${message}`);
return `returned: ${message}`;
}
}
// extends test.prototype.doIt()
// (you could also just extend the instance below if desired)
extender(
test.prototype,
'doIt',
function () { console.log(`prepended: ${this.x}`) },
function () { console.log(`appended: ${this.x}`) }
);
// See if the prepended and appended code runs
let tval = new test().doIt('log this');
console.log(tval);