Именование анонимной функции
Можно ли как-то установить имя для анонимных функций?
Нет необходимости добавлять имена функций в пространство имен для анонимных функций, но я хотел бы избежать увидеть большое количество (?) в моем отладчике javascript, чтобы я мог поддерживать трассировку стека вызовов информативной.
Также я могу безопасно передавать обычные объявленные функции в качестве аргументов вместо анонимных функций, или я буду входить в некоторые странные ошибки. Кажется, что это работает.
$("object").bind("click", function() { alert("x"); });
$("object").bind("click", function debuggingName() { alert("x"); });
[изменить]
Я имел в виду что-то вроде
$("object").bind("click", function() { Function.Name = "debuggingName"; alert("x"); });
Ответы
Ответ 1
В вашем втором примере используется именованное выражение функции, которое отлично работает в большинстве браузеров, но имеет некоторые проблемы в IE, о которых вы должны знать, прежде чем использовать его. Я рекомендую читать kangax отличную статью по этому вопросу.
Ответ 2
Вы можете сделать что-то подобное с помощью функций со стрелками, это работает для меня на Node.
const createTask = ([name, type = 'default']) => {
const fn = () => { ... }
Object.defineProperty(fn, 'name', {
value: name,
configurable: true,
})
return fn
}
MDN несколько вводит в заблуждение здесь:
Вы не можете изменить имя функции, это свойство доступно только для чтения...
Чтобы изменить его, вы можете использовать Object.defineProperty().
Этот ответ предоставляет более подробную информацию.
Ответ 3
Я обычно делаю: $ ( "Объект" ). Bind ("click" , имя функции() { предупреждение ( "х" ); });
и не сталкиваются с какими-либо проблемами.
Это рекомендуется в некоторых из основных библиотек:
https://groups.google.com/forum/m/#!topic/firebug/MgnlqZ1bzX8
http://blog.getfirebug.com/2011/04/28/naming-anonymous-javascript-functions/
Ответ 4
Если динамическое имя функции является проблемой. Вы можете попробовать это:
function renameFunction(name, fn) {
return (new Function("return function (call) { return function " + name +
" () { return call(this, arguments) }; };")())(Function.apply.bind(fn));
}
renameFunction('dynamicName',function() { debugger })();
источник: Нейт Ферреро
Ответ 5
С помощью спецификации языка ECMAScript2015 (ES2015, ES6) можно обойтись без использования медленной и небезопасной функции eval и без метода Object.defineProperty, который и повреждает объект функции, и не работать в некоторых важных аспектах в любом случае.
См., Например, эту функцию nameAndSelfBind
, которая способна как именовать анонимные функции, так и переименовывать именованные функции, а также привязывать свои собственные тела к себе и хранить ссылки на обработанные функции для использования во внешней области (JSFiddle):
(function()
{
// an optional constant to store references to all named and bound functions:
const arrayOfFormerlyAnonymousFunctions = [],
removeEventListenerAfterDelay = 3000; // an auxiliary variable for setTimeout
// this function both names argument function and makes it self-aware,
// binding it to itself; useful e.g. for event listeners which then will be able
// self-remove from within an anonymous functions they use as callbacks:
function nameAndSelfBind(functionToNameAndSelfBind,
name = 'namedAndBoundFunction', // optional
outerScopeReference) // optional
{
const functionAsObject = {
[name]()
{
return binder(...arguments);
}
},
namedAndBoundFunction = functionAsObject[name];
// if no arbitrary-naming functionality is required, then the constants above are
// not needed, and the following function should be just "var namedAndBoundFunction = ":
var binder = function()
{
return functionToNameAndSelfBind.bind(namedAndBoundFunction, ...arguments)();
}
// this optional functionality allows to assign the function to a outer scope variable
// if can not be done otherwise; useful for example for the ability to remove event
// listeners from the outer scope:
if (typeof outerScopeReference !== 'undefined')
{
if (outerScopeReference instanceof Array)
{
outerScopeReference.push(namedAndBoundFunction);
}
else
{
outerScopeReference = namedAndBoundFunction;
}
}
return namedAndBoundFunction;
}
// removeEventListener callback can not remove the listener if the callback is an anonymous
// function, but thanks to the nameAndSelfBind function it is now possible; this listener
// removes itself right after the first time being triggered:
document.addEventListener("visibilitychange", nameAndSelfBind(function(e)
{
e.target.removeEventListener('visibilitychange', this, false);
console.log('\nEvent listener 1 triggered:', e, '\nthis: ', this,
'\n\nremoveEventListener 1 was called; if "this" value was correct, "'
+ e.type + '"" event will not listened to any more');
}, undefined, arrayOfFormerlyAnonymousFunctions), false);
// to prove that deanonymized functions -- even when they have the same 'namedAndBoundFunction'
// name -- belong to different scopes and hence removing one does not mean removing another,
// a different event listener is added:
document.addEventListener("visibilitychange", nameAndSelfBind(function(e)
{
console.log('\nEvent listener 2 triggered:', e, '\nthis: ', this);
}, undefined, arrayOfFormerlyAnonymousFunctions), false);
// to check that arrayOfFormerlyAnonymousFunctions constant does keep a valid reference to
// formerly anonymous callback function of one of the event listeners, an attempt to remove
// it is made:
setTimeout(function(delay)
{
document.removeEventListener('visibilitychange',
arrayOfFormerlyAnonymousFunctions[arrayOfFormerlyAnonymousFunctions.length - 1],
false);
console.log('\nAfter ' + delay + 'ms, an event listener 2 was removed; if reference in '
+ 'arrayOfFormerlyAnonymousFunctions value was correct, the event will not '
+ 'be listened to any more', arrayOfFormerlyAnonymousFunctions);
}, removeEventListenerAfterDelay, removeEventListenerAfterDelay);
})();
Ответ 6
Анонимная функция - это функция без имени, она выполняется из того, где она определена. В качестве альтернативы вы можете определить функцию отладки перед ее использованием.
function debuggingName() {
alert("x");
}
$("object").bind("click", debuggingName);