Как `arguments.callee` относится к анонимным функциям?
Сценарий был необходим, чтобы быстро сказать мне, сколько HTML-комментариев есть на странице и каково их содержание. Использование анонимной функции для рекурсивного обхода DOM представляется целесообразным:
var comments = []; //set up an array where comment contents will be copied to
(function(D) {
if (8===D.nodeType) comments.push(D.nodeValue); //check if node is a comment
D=D.firstChild;
while (D) {
arguments.callee(D); //recursively look for comments...
D=D.nextSibling; //...and remember to iterate over all children of any node
}
})(document);
console.log(comments.join("\r\n")); //list all comments
Fiddle работает, как и ожидалось, но мне было любопытно, действительно ли это была одна и та же функция, вызываемая снова и снова, или было несколько ссылок на исходную вызванную функцию, или было несколько идентичных вызванных функций... В конце концов, не было названных ссылка сделана, так как это будет работать, когда обход идет глубже? Я думал, что смогу проверить это, добавив следующий код в while (D) {...}
//tmpCallee has been declared
if (tmpCallee) {
console.warn(arguments.callee === tmpCallee);//true
/*great, means these should be both pointing to the same function*/
console.log(arguments.callee === arguments.caller);//false
/*wait, what? didn't we just establish above that
all of our functions called recursively would be the same?*/
console.log(arguments.caller);//undefined... but it was called recursively!
console.log(arguments.callee);//prints our function code verbatim as it should
}
tmpCallee = arguments.callee;
Я не совсем понимаю. 1) я действительно вызываю одну и ту же функцию снова и снова, или вызывается несколько идентичных функций, или что-то еще в игре? 2) почему arguments.caller
не указывает на нашу функцию? это было ясно вызвано этим - вот как работает рекурсия, нет?
3 ответа
действительно ли я вызываю одну и ту же функцию снова и снова, или же вызывается несколько идентичных функций или что-то еще?
Да, у вас есть только один экземпляр функции, к которому вы обращаетесь все время. Тем не менее, вы настраиваете стек вызовов, в котором локальные переменные (в вашем случае аргумент D
) будет сохранен для каждого вызова.
почему arguments.caller не указывает на нашу функцию?
Здесь нет caller
собственность на arguments
объект, он был удален. Вы, вероятно, имели в виду caller
свойство объекта функции, которое является нестандартным, но все еще пригодным для использования (хотя запрещено в строгом режиме, а также argments.callee
).
Здесь задействован только один экземпляр функции. Эта функция вызывает себя рекурсивно. Вы можете легко проверить это, назначив имя для выражения функции в вашем коде:
(function fn (D) {
а затем, внутри тела:
fn === arguments.callee // => true
Вышеприведенное будет верно для каждого вызова, показывая, что в этом процессе была создана и вызвана только одна функция.
Также это:
arguments.callee === arguments.callee.caller // => true, except first time
показывает, что функция вызывает себя, то есть вызывающий является вызываемым. Вышеприведенное выражение верно для каждого вызова, кроме первого, поскольку первый вызов произошел из глобального кода.
Демонстрация в реальном времени: http://jsfiddle.net/HbThh/2/
Здесь нет caller
собственность для arguments
ты должен использовать arguments.callee.caller
получить caller
,