Передача аргументов в анонимных функциях в JavaScript

Иногда я вижу JavaScript, который написан с аргументом, который уже имеет заданное значение или является объектом с методами. Возьмите пример jQuery, например:

$(".selector").children().each(function(i) {
    console.log(i);
});

При регистрации i вы получите значение того, что i нахожу в этой итерации, когда смотрю на дочерних селекторов в each методе jQuery.

Возьмите пример Node.js:

http.createServer(function(request, response) {
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.write("Hello World");
    response.end();
}).listen(8888);

Здесь вы можете увидеть, что request и response передаются, и они содержат свои собственные методы, на которые можно воздействовать.

Для меня это похоже на передачу функции функции createServer с двумя аргументами, у которых уже есть методы.

Мой вопрос многогранный:

  1. Откуда берутся эти аргументы?
  2. Если это просто анонные функции, как они получают аргументы, которые могут действовать как другие функции?
  3. Как создать функции, которые могут принимать мои собственные аргументы?
  4. Использует ли это силу закрытия?

Ответ 1

Для меня это похоже на передачу функции функции createServer с двумя аргументами, у которых уже есть методы.

Нет. Они передавали функцию createServer которая принимает два аргумента. Эти функции позже будут вызываться с любым аргументом, который вводит вызывающий. Например:

function caller(otherFunction) {
     otherFunction(2);
 }
caller(function(x) {
    console.log(x); 
});

Будет печатать 2.

Более продвинутый, если это не то, что вы хотите, вы можете использовать метод привязки, принадлежащий ко всем функциям, который создаст новую функцию с уже связанными аргументами. например:

caller(function(x) {
    console.log(x);
}.bind(null, 3);
});

Теперь напечатаем 3, и аргумент 2, переданный анонимной функции, станет неиспользуемым и неназванным аргументом.

Во всяком случае, это плотный пример; проверьте связанную документацию для bind чтобы понять, как привязка работает лучше.

Ответ 2

Давайте рассмотрим $.each для примера:

each: function (obj, callback, args) {
    var value,
    i = 0,
        length = obj.length,
        isArray = isArraylike(obj);

    if (args) {
        if (isArray) {
            for (; i < length; i++) {
                value = callback.apply(obj[i], args);

                if (value === false) {
                    break;
                }
            }
        } else {
            for (i in obj) {
                value = callback.apply(obj[i], args);

                if (value === false) {
                    break;
                }
            }
        }

        // A special, fast, case for the most common use of each
    } else {
        if (isArray) {
            for (; i < length; i++) {
                value = callback.call(obj[i], i, obj[i]);

                if (value === false) {
                    break;
                }
            }
        } else {
            for (i in obj) {
                value = callback.call(obj[i], i, obj[i]);

                if (value === false) {
                    break;
                }
            }
        }
    }

    return obj;
}

Это вызвано из

$(".selector").children().each(function(i) {
    console.log(i);
});

как:

return $.each.call(this, callback /* this is your function */, args /* which is an additional thing people rarely use*/ )

Это строка (в первом блоке), на которой вы хотите посмотреть

callback.call(obj[i], i, obj[i]);

Он вызывает обратный вызов и передает объект как контекст - вот почему вы можете использовать this в цикле. Затем итерация i а затем тот же объект, что и контекст, отправляется как аргументы для обратного вызова. Это немного похоже на волшебство; пока вы не посмотрите на исходный код.

Ответ 3

Да, вы передаете функции в качестве аргументов. Разумеется, функции, которые вы проходите, имеют свои собственные аргументы.

И эти аргументы могут быть любыми, включая объекты, которые могут иметь свои собственные методы и т.д.

http.createServer примет функцию, и он будет знать, как могут аргументы, которые имеют функцию. Один из способов сделать это - проверить свойство arguments переданной функции. Или разработчик api мог использовать фактические элементы.

Писатель этой функции будет знать, что ожидается в качестве аргументов, и задокументирует его в api documentation.

Ответ 4

Если вы посмотрите на код для createServer, он будет выглядеть примерно так:

function createServer (handleRequestAndResponseFunction) {
    handleRequestAndResponseFunction(actualRequest, actualReponse);
}

хорошо, нет, это не так, но это простой пример. createServer принимает function которая принимает два аргумента.

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

Ответ 5

Здесь приведен пример передачи параметров в анонимную функцию

    var a = 'hello';

    // Crockford
    (function(a){alert(a)}(a));

    // Others
    (function(a){alert(a)})(a);

Он использует закрытие, поскольку это анонимная функция (на самом деле все зависит от того, как вы ее написали)