Функция JS, возвращающая другую функцию - PullRequest
0 голосов
/ 28 апреля 2010

Я хочу понять о переменных, которые использовались в возвращаемой функции. Это пример кода

Prototype = {}

Prototype.F =
{
  bind: function()
  {
    var args = arguments, __method = args.shift(), object = args.shift();
    return function()
    {
        return __method.apply(object, args.concat(arguments));
    }
  }
}

function ObjectA()
{
    ...
    this.addListener = Prototype.F.bind(this.eventSource.addListener,
        this.eventSource);
    ...
}


var a = ObjectA();
a.addListener(this); // assuming 'this' here will point to some window object

Как я понимаю, возвращаемая функция в bind () не оценивается, пока не будет вызвана в последней строке. Это нормально, чтобы принять. Так addListener будет содержать тело функции, содержащее «apply».

Но что я не понимаю, когда addListener вызывается, какие параметры он будет иметь? в частности _method и args всегда будут неинициализированы?

Ответы [ 3 ]

1 голос
/ 28 апреля 2010

Функция, которую возвращает bind, является замыканием над аргументами функции bind, поэтому аргумент __method будет первым аргументом bind (в вашем примере вызова , это будет функция this.eventSource.addListener).

Замыкания - это, в основном, функции, в которые встроены данные. Вот более простой пример:

function makeAlert(msg) {
    return function() {
        alert(msg);
    }
}
var myalert = makeAlert("Hi there!");
myalert(); // Alerts "Hi there!"

Функция, возвращаемая makeAlert, «закрывает» (сохраняет доступ) объекты в области действия в вызове функции makeAlert, который ее создал, включая аргумент msg. Вот почему, когда мы вызываем функцию позже, она все еще имеет msg, хотя вызов к makeAlert давно завершен. Подробнее о замыканиях здесь.

Ключевым моментом, который следует помнить о замыканиях, является то, что они сохраняют доступ к всему , находящемуся в области их определения, а не только к тем вещам, которые они явно используют. Так, например:

function init() {
    var data;

    data = /* ...build some really big array of data...*/;

    document.getElementById('foo').onclick = function() {
        this.style.display = "none";
    };
}

Хотя обработчик событий не имеет ничего общего с массивом больших данных, он сохраняет ссылку на него и сохраняет эти данные в памяти после завершения вызова init. Это связано с тем, что он имеет ссылку на скрытый объект (условно называемый «переменным объектом»), который является контейнером для всех аргументов и локальных переменных в области действия, в которой он определен. (В этом конкретном случае, если вам не нужны все эти данные, просто установите data в undefined в конце. Обработчик события все равно будет иметь ссылку на data, но эта ссылка не содержит массив, так что память массива может быть восстановлена.)

0 голосов
/ 28 апреля 2010

в области действия функции arguments - это массивоподобный объект, который содержит значения, предоставляемые при вызове функции, независимо от того, определены ли в определении функции параметры.

так для этого звонка:

Prototype.F.bind(this.eventSource.addListener, this.eventSource);

, что приводит к этому:

var args = arguments, __method = args.shift(), object = args.shift();

arguments содержит 2 элемента: все, что this.eventSource.addListener и this.eventSource указывают на то, когда вызывается функция. эта коллекция из 2 предметов копируется в args, а затем предметы перемещаются из коллекции в __method и object.

, так как вызов bind фактически генерирует другую функцию, экземпляр arguments в новой функции будет другим - он будет иметь параметры, предоставленные во время этого вызова. исходный arguments из вызова к bind сохраняется в args и объединяется с arguments из более позднего вызова функции.

0 голосов
/ 28 апреля 2010

_method и args будут всегда инициализированы, потому что вы определяете их при первом вызове

this.addListener = Prototype.F.bind(this.eventSource.addListener, this.eventSource);

Там вы получите, что _method будет this.eventSource.addListener, и аргументы будут этими обоими аргументами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...