Замыкания в JavaScript используются довольно часто, и вы, наверняка, уже сталкивались с ними. Они позволяют делать код более выразительным и лаконичным. В какой-то степени, замыкания могут показаться сложной темой, но в данной статье мы постараемся разобраться с ними. Перед знакомством с этой темой необходимо хорошо понимать, какие особенности имеет область видимости переменных в JavaScript.
Замыкание — это функция, объявленная внутри другой функции и имеющая доступ к переменным внешней (вмещающей) функции. Замыкание имеет доступ сразу к трем областям видимости:
Внутренняя функция имеет доступ не только к переменным внешней функции, но и к параметрам внешней функции. Обратите внимание, что внутренняя функция не может использовать объект arguments внешней функции, однако, имеет доступ к параметрам внешней функции напрямую.
Простыми словами замыкание — это функция, описанная внутри другой функции.
Пример замыкания в JavaScript:
function showName(firstName, lastName) {
var nameIntro = "Your name is ";
function makeFullName() {
return nameIntro + firstName + " " + lastName;
}
return makeFullName();
}
showName("Michael", "Jackson"); // Your name is Michael Jackson
Замыкания также нередко используются в jQuery:
$(function() {
var selections = [];
$('.niners').click(function() {
selections.push(this.prop('name'));
});
});
Замыкание имеет доступ к переменным внешней функции даже после ее выполнения.
Одним из наиболее тонких моментов, связанных с замыканиями, является то, что внутренняя функция продолжает иметь доступ к области видимости внешней даже после того, как внешняя выполнилась.
Это означает, что даже после того, как внешняя функция выполнилась, внутренняя функция все еще может быть вызвана и она все еще имеет доступ к переменным внешней функции.
Замыкания хранят ссылки на переменные внешней функции, а не фактические значения.
Такая интересная особенность позволяет описывать приватные переменные. Это способ впервые был предложен Дугласом Крокфордом:
function user() {
var name = 'Unknown';
return {
getName: function() {
return name;
},
setName: function(newName) {
name = newName;
}
}
}
var testUser = user();
testUser.getName(); // Unknown
testUser.setName('John Smith'); // Изменяем значение приватной переменной
testUser.getName(); // John Smith
Т.к. замыкание хранит ссылку на переменную внешней функции, а не фактическое значение, могут возникать побочные эффекты, связанные с тем, что замыкание изменяет внешнюю переменную:
function userIdGenerator(users) {
var i;
var uniqueId = 100;
for (i = 0; i < users.length; i++) {
users[i]['id'] = function() {
return uniqueId + i;
}
}
return users;
}
var testUsers = [{ name: "Smith", id:0 }, { name: "Johnson", id:0 }, { name: "Thompson", id:0 }];
var testUsersIds = userIdGenerator(testUsers);
var firstId = testUsersIds[0];
console.log(firstId.id()); // 103
В предыдущем примере, к тому времени, когда вызывается анонимная функция, значение i становится равно 3 (длина массива). Число 3 было прибавлено к значению переменной uniqueId, тем самым для всех элементов массива testUsers значение id стало равно 103, вместо предполагаемых 100, 101, 102.
Решением предыдущей проблемы может быть шаблон немедленно вызываемой функции (Immediately Invoked Function Expression — IIFE):
function userIdGenerator(users) {
var i;
var uniqueId = 100;
for (i = 0; i < users.length; i++) {
users[i]['id'] = function(j) {
return function() {
return uniqueId + j;
} ();
} (i);
}
return users;
}
var testUsers = [{ name: "Smith", id:0 }, { name: "Johnson", id:0 }, { name: "Thompson", id:0 }];
var testUsersIds = userIdGenerator(testUsers);
var firstId = testUsersIds[0];
console.log(firstId.id); // 100
var secondId = testUsersIds[1];
console.log(secondId.id); // 101
Замыкания — это очень интересный и крайне полезный прием программирования. Суть замыкания можно выразить так: в функции доступны все переменные той области видимости, в которой она была определена.
Замыкания позволяют реализовывать аналог приватных переменных, минимизировать выход переменных в глобальную область видимости. С другой стороны, неаккуратное использование замыканий может привести к побочным эффектам, описанным выше. Поэтому использовать их стоит крайне внимательно.
Попалась интересная задачка, на баннере нужно было выводить «Акция действует до (тут последний день месяца)», решил сделать это на Javascript, ну чтоб не лазить каждый раз в код для правок, вот что получилось
Написание хорошо переиспользуемого кода иногда может быть сложным. Мы можем программировать на разных языках и придерживаться определенных ограничений или шаблонов, которые несут смысл от конкретного контекста.
В JavaScript существует несколько основных типов данных. В этой статье мы получим о них общее представление, а позже, в соответствующих главах подробно познакомимся с использованием каждого типа в отдельности.