Что это за конструкция кода, охватывающая части библиотеки и для чего она нужна?
Я имитировал библиотеку и смог написать следующий код. Этот код создан 'c'
объект к которому 'a'
функция назначена. Итак, позвонить 'a'
Мне придется написать c.a()
,
Кроме того, я смог добавить больше функций к этому 'c'
объект. Я хочу понять, что происходит в этом коде. Это не похоже на нормальное объектно-ориентированное программирование. Как называется этот тип программирования на JavaScript?
var c = (function(c) {
if (c === undefined) {
c = {};
}
function a() {
alert(1);
}
c.a = a;
return c;
}(c));
6 ответов
Это шаблон модуля. Вы увидите много вариантов этого паттерна, поэтому важно понимать, что на самом деле происходит, нельзя просто имитировать один.
Смысл этого куска кода заключается в завершении объекта c
(обычно ваша глобальная библиотека). Вероятно, у вас в приложении много похожих фрагментов кода, все части построения c
Вероятно, каждый из них в своем собственном файле.
В случае, если объект библиотеки c
, который передается в качестве аргумента функции, еще не существует (c === undefined
), он создан. Это позволяет не зависеть от порядка выполнения или от предварительно выполненного файла.
Правая часть назначения - это IIFE (выражение для немедленного вызова функции), то есть функция, которая вызывается немедленно. Преимущество этой конструкции в том, что она создает область, в которой переменные (например, a
функция) может быть объявлена без загрязнения внешней (глобальной) области видимости. Здесь дело в том, что a
в любом случае является внешним, но модуль обычно зависит от нескольких внутренних (частных) функций и переменных.
Подробности, которые могут нуждаться в объяснении: все эти файлы выглядят так, как будто они определяют новую переменную c
но здесь нет проблем, даже если файлы объединены: var
операторы не определяют новую переменную, если она уже существует (переменная определена для всей области видимости, здесь глобально, даже до точки объявления).
Еще один способ написать это было бы
var c = c || {}; // ensure the c variable is defined, and initialize its value it if necessary
(function() { // let's use an IIFE to have a protected scope and not pollute the global one
function a() {
alert(1);
}
c.a = a; // let's augment c
})();
Этот, вероятно, яснее, чем
- он явно разделяет два шага (
c
инициализация иc
завершение с использованием IIFE) - это не зависит от двух
c
переменные с тем же именем - это менее многословно
Вот тот же код с добавленными комментариями о том, что делает каждая строка, и что происходит, когда мы ее пропускаем.
//Here, we're defining a function that will return an object.
//its only parameter is named 'c'
//this is confusing, since the parameter has the same name as the global definition of the function.
//the var c definition is the global definition. the function parameter is not.
//so every reference to anything named 'c' inside the function definition is local.
var c = (function(c)
{
//if c (the c we passed as a parameter) is not yet defined
if (c === undefined) {
//define c as an object
c = {};
}
//define a function
function a() {
alert(1);
}
//attach it to the object
c.a = a;
//return the object
return c;
}(c)); // call the constructor we just defined, using the global definition of `c`.
// the first time we pass this point, c as a variable is still undefined.
var c = (function(c) {
if (c === undefined) {
c = {};
}
function a() {
alert(1);
}
c.a = a;
return c;
}(c));
Давайте рассмотрим шаг за шагом.
var c =
инициализация переменной с именем c. Обратите внимание, что в этот момент, если переменная с именем c уже инициализирована, c
будет ссылаться на это значение только до тех пор, пока мы не достигнем конца этой декларации.
( .... )
Это означает, что все, что находится внутри, должно рассматриваться как выражение.
function(c)
означает, что это "выражение" является функцией, которая принимает аргумент. Этот аргумент отныне будет называться именем c
пока функция не закончена. Любая переменная с именем c
который был объявлен вне области действия функции, таким образом, не был бы доступен непосредственно здесь. Хотя, если он находится в глобальной области видимости, а глобальной областью видимости является объект окна, его можно назвать window.c
,
if (c === undefined) { ... }
проверяет, является ли переданный ему аргумент неопределенным или нет. Вернет true, если он не определен, и, таким образом, выполнит все, что находится внутри блока if.
c = {}
установить переменную c
на пустой объект. Поэтому, если аргумент был (передан или) неопределен, мы определяем его здесь (и определяем его для пустого объекта....).
function a() { alert(1); }
объявил функцию с именем a
вызов которого приведет к предупреждению числа 1. Обратите внимание, что это просто объявление функции. Мы еще не вызывали функцию.
c.a = a
Аргумент c
теперь назначено свойство с именем a
что относится к функции a
мы только что создали.
return c
вырваться из функции с возвращаемым значением в качестве конечного значения c
После внесения изменений мы сделали, чтобы аргумент прошел.
(fun...}(c))
вызовите функцию, которую мы только что создали, и передайте ей в качестве аргумента текущее значение c
, поскольку мы вызывали функцию как выражение, результатом этого выражения будет любое возвращаемое значение функции. И наша функция возвращает объект (который мы передали ему) после присвоения ему свойства.
Поскольку это выражение было приравнено к переменной c
возвращаемое значение выражения (которое является возвращаемым значением функции) теперь хранится в переменной c
,
Если вы прочитаете все это правильно, вы будете знать, что переменная c
теперь будет содержать объект, который будет иметь свойство a
это функция, которая предупреждает число 1. И этот объект также сохраняет свойства, которые он мог иметь раньше.
Если мы отключим этот код, чтобы сделать его читаемым, просто сделав имена переменных описательными:
var myObject = (function(someObject) {
if (someObject === undefined) {
someObject = {};
}
function alertOne () {
alert(1);
}
someObject.alertOne = alertOne;
return someObject;
}(myObject));
Это шоу представляет собой эпизод из серии, раскрывающий шаблон модуля, который рассказывает нам о том, как элегантно добавить дополнительные свойства к объекту, который был объявлен ранее, без загрязнения глобальной области видимости. В главных ролях выражения немедленно вызванных функций (IIFE).
Почему в конце мы снова написали (с))?
Это называется сразу вызываемой функцией.
(function(received argument){
//some code here.......
})(passed argument) //<-- here the function is invoked
c
это переданный аргумент. Функция вызывается сразу после ее создания. Этот тип объявлений используется для сохранения конфиденциальности переменных и поддержания чистоты глобального пространства имен.
Шаблон в вашем коде используется для создания модулей.
............ Теперь перейдите к вашему коду:............
если переданный аргумент не определен: .............
Во-первых, ...}(c))
эта часть немедленно вызванной функции вызывается. Она передается с аргументом, называемым c
который еще не определен. (function(c){...
часть получить это c
аргумент.
Здесь сначала passed argument c
не определено. if(c==undefined)
срабатывает. На данный момент, используя c={}
утверждение, неопределенный объект c
назначен empty object
,
Вот function a() { //... }
это частный метод, созданный внутри модуля. К нему нельзя получить глобальный доступ.
Частный метод a
Это делается глобально доступным путем назначения его с помощью C c.a=a
Statement. Таким образом, когда объект вернется, вы можете вызвать этот метод в глобальном контексте.
Таким образом вновь созданный пустой объект c
назначен метод, называемый a
. Затем он возвращается и var c
получить этот объект.
если переданный аргумент не является неопределенным:............
Но если passed c
является not undefined
скажем, если объект передается, то новый объект не создается. Я имею в виду, если if(c==undefined)
является ложным. Так что это не выполняется. Я имею в виду, что новый пустой объект не создается. Затем переданному объекту назначается новый метод с именем a
с помощью c.a=a
Это так просто.
Код ниже - намного более простая версия вашего кода. Он автоматически отправит пустой объект, если он изначально не определен. Так что вам не нужно проверять, является ли он неопределенным или нет. Это называется свободным дополнением.
var c = (function(c) {
function a() {
alert(1);
}
c.a = a;
return c;
}(c || {} ));
Эта статья, написанная Беном Черри, помогла мне понять этот тип паттерна: http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html
Выдержка из статьи:
Анонимные Закрытия
Это фундаментальная конструкция, которая делает все это возможным, и действительно единственная лучшая особенность JavaScript. Мы просто создадим анонимную функцию и сразу запустим ее. Весь код, который выполняется внутри функции, находится в закрытом состоянии, что обеспечивает конфиденциальность и состояние в течение всего срока службы нашего приложения.
(function () {
// ... all vars and functions are in this scope only
// still maintains access to all globals
}());
Обратите внимание на ()
вокруг анонимной функции. Это требуется языком, поскольку операторы, начинающиеся с функции токена, всегда считаются объявлениями функций. В том числе ()
вместо этого создает выражение функции.
Глобальный импорт
JavaScript имеет функцию, известную как подразумеваемые глобальные переменные. Всякий раз, когда используется имя, интерпретатор перемещается по цепочке контекста в обратном направлении в поисках оператора var для этого имени. Если ничего не найдено, эта переменная считается глобальной. Если он используется в назначении, глобальный создается, если он еще не существует. Это означает, что использовать или создавать глобальные переменные в анонимном закрытии легко. К сожалению, это приводит к сложному управлению кодом, поскольку не очевидно (для людей), какие переменные являются глобальными в данном файле.
К счастью, наша анонимная функция предоставляет простую альтернативу. Передавая глобальные переменные в качестве параметров нашей анонимной функции, мы импортируем их в наш код, который одновременно более понятен и быстрее, чем подразумеваемые глобальные переменные. Вот пример:
(function ($, YAHOO) {
// now have access to globals jQuery (as $) and YAHOO in this code
}(jQuery, YAHOO));
Модуль Экспорт
Иногда вы не просто хотите использовать глобальные переменные, но вы хотите объявить их. Мы можем легко сделать это, экспортируя их, используя возвращаемое значение анонимной функции. Это завершит базовый шаблон модуля, поэтому вот полный пример:
var MODULE = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {
// ...
}
my.moduleProperty = 1;
my.moduleMethod = function () {
// ...
};
return my;
}());
Обратите внимание, что мы объявили глобальный модуль с именем MODULE
с двумя открытыми свойствами: метод с именем MODULE.moduleMethod
и переменная с именем MODULE.moduleProperty
, Кроме того, он поддерживает закрытое внутреннее состояние, используя закрытие анонимной функции. Кроме того, мы можем легко импортировать необходимые глобальные переменные, используя шаблон, который мы изучили выше.
Что вы делаете, это объявляете анонимную функцию, а затем вызываете ее с параметром c
и присвоение его переменной, также называемой c
что очень смущает:-)
Переименование переменных это то, что у вас есть:
var result=(function (input_parameter){...} (parameter_used_to_call_my_function));
Финал (c)
Вы спрашиваете об этом параметре для вызова функции. Проще увидеть, если вы используете более длинный синтаксис:
var my_function=function(input_parameter){...};
var result=my_function(result);
Также стоит отметить, что вы звоните my_function
с помощью result
(хотя ты назвал это c
) в качестве параметра, который также является именем переменной, которую вы только что создали для хранения возвращаемого значения функции. JS согласен с этим, потому что он не строг в том, как вы обрабатываете переменные, но это запутанный способ написания кода. Вы объявляете переменную и передаете ее (переменную с таким именем, которая на тот момент не должна существовать) в качестве параметра вашей функции на тот случай, если она была объявлена ранее (и заботитесь об этом случае внутри функции, которая по крайней мере согласуется).
Что происходит внутри my_function
является то, что вы проверяете, имеет ли ваш параметр предыдущее значение (что я объяснил, если предыдущий параграф); если он был неопределенным, вы инициализируете его пустым объектом. Затем вы добавляете функцию к input_parameter
и верни это.
Я не знаю, есть ли название для этого типа программирования, но использование одного и того же имени переменной для разных вещей не выглядит хорошей идеей:-)