Как `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,

Другие вопросы по тегам