В этом топике я хочу рассказать о необычных конструкциях js, а так же на наглядных примерах разобрать некоторые моменты, связанные с объектами и вызовами методов, которые, при использовании нетривиального синтаксиса могут вызывать вопросы у почти всех начинающих использовать js.
Цель топика (и сразу же дисклеймер) — помочь начинающим не впадать в кататонический ступор при виде чего-то вроде
И ещё один дисклеймер. Я ни в коем случае не призываю оформлять исходный код таким образом и даже прошу никогда так не делать. Но, ситуации в жизни бывают разные и, возможно, окажется полезным уметь читать разные монстроидальные конструкции. Врага, как говорится, нужно знать в лицо. Но, тем не менее некоторые ингредиенты этой кашки могут оказаться весьма полезными в определённых ситуациях.
Это — объект со свойством property и методом method, обратиться к которым можно несколькими способами:
можно записать короче:
или ещё короче, чему способствует низкий приоритет тернарного оператора:
В свете вышеописанного, что-то в исходном примере становится яснее, но разберём мы его от и до. Итак, вот наша мозголомка:
Некий жопа-программист Ваш покорный слуга решил сэкономить несколько байт кода и записал в одну строку решение задачи «проверить предпочтения объекта user касательно операционных систем разных производителей и, в зависимости от квалификации пользователя разрешить ему установить систему или же отправить на повышение квалификации». Объектная модель выглядит так (все совпадения, разумеется, случайны и я прошу никого не обижаться: все параллели проводятся just for lulz):
Во-первых, поступим как известный итальянский скульптор и отсечём всё лишнее. Получится следующего вида конструкция:
Сразу видно, что в зависимости от результата некоторого условия вызывается соответствующий метод объекта user. А именно, install в случае, если условие истинно и cant_install, если ложно. Обоим методам передаётся нечто в качестве параметра. Предлагаю разобраться именно с этим нечтом:
Нечто — название желаемой операционной системы в зависимости от предпочтений пользователя. Диктую по буквам: если пользователь предпочитает продукты Микрософта, то мы читаем свойство system объекта microsoft. Если нет, то тоже свойство читается у объекта apple. Если такого свойства не существует (вендекапец-там или ещё что-то нехорошее), то пользователю, кроме Линукса ничего не остаётся. Таким образом, мы получаем один из трёх вариантов (см. объектную модель):
В условии, которое определяет вызывать ли метод install или же cant_install у объекта user, мы таким же образом докапываемся до свойства install_carma, в зависимости от пользовательских предпочтений и «ситуации на рынке» и сравниваем значение этого свойства со значением свойства carma и объекта user. Если карма пользователя достаточна, то всё в порядке — вызываем метод user[«install»]. Если же нет, то тоже всё в порядке, но вызываем метод user[«cant_install»] и передаём вызванному в качестве параметра название системы.
Я ещё раз повторюсь, что статья рассчитана в первую очередь на начинающих Javascript-программистов, которым по долгу службы придётся столкнуться с самым разным «чужим кодом», который надо будет читать. Кроме того, ряд примеров нетривиального js-синтаксиса может пригодиться в некоторых случаях, но (sic!) ещё и ещё раз напоминаю, что в статье приведён пример как делать не надо! Старайтесь всегда писать красивый и читабельный код. И я не удержусь от того, чтобы не процитировать известный афоризм: «Пишите код, исходя из того, что все программисты, которые будут сопровождать вашу программу, — склонные к насилию психопаты, знающие, где вы живёте.»
Цель топика (и сразу же дисклеймер) — помочь начинающим не впадать в кататонический ступор при виде чего-то вроде
user[(os[((user.microsoft_adept ? microsoft : apple).system || "linux")].install_carma <= user.carma) ? "install" : "cant_install"](os[((user.microsoft_adept ? microsoft : apple).system || "linux")].name);
И ещё один дисклеймер. Я ни в коем случае не призываю оформлять исходный код таким образом и даже прошу никогда так не делать. Но, ситуации в жизни бывают разные и, возможно, окажется полезным уметь читать разные монстроидальные конструкции. Врага, как говорится, нужно знать в лицо. Но, тем не менее некоторые ингредиенты этой кашки могут оказаться весьма полезными в определённых ситуациях.
Приступим, помолясь и по-порядку
Объекты, свойства и методы
var obj = {
property: 0,
method: function() {}
}
Это — объект со свойством property и методом method, обратиться к которым можно несколькими способами:
obj.property; //каноничный, используется чаще всего
obj.method();
obj["property"]; //чуть реже, но тоже используется
obj["method"]();
Тернарный оператор
Нужен для простой записи несложной условной конструкции. Так, например, следующее условиеif (a > b) {
console.log("a больше b");
}
else {
console.log("a меньше или равно b");
}
можно записать короче:
(a > b) ? console.log("a больше b") : console.log("a меньше или равно b");
или ещё короче, чему способствует низкий приоритет тернарного оператора:
console.log( (a > b) ? "a больше b" : "a меньше или равно b" );
Условный оператор ||
В Javascript интересен тем, что возвращает первое ненулевое значение, что удобно для задания значений по умолчанию.function get_object(id) {
return document.getElementById(id) || "Объект не найден"; //Функция поиска объекта по id вернёт строку «Объект не найден», если указан несуществующий идентификатор
}
function do_something() {
return false || 0 || Math.PI || "Что за дебильный пример?"; //Функция вернёт число пи
}
Возвращаемся к нашим баранам
В свете вышеописанного, что-то в исходном примере становится яснее, но разберём мы его от и до. Итак, вот наша мозголомка:
user[(os[((user.microsoft_adept ? microsoft : apple).system || "linux")].install_carma <= user.carma) ? "install" : "cant_install"](os[((user.microsoft_adept ? microsoft : apple).system || "linux")].name);
var user = {
microsoft_adept: false, //любит ли пользователь продукты Микрософта
carma: 10, //условная квалификация пользователя
install: function(system) { console.log("I'am installing " + system + "!"); },
cant_install: function(system) { console.log("I can't install " + system + "..."); }
}
var os = {
windows: {
name: "Windows",
install_carma: 30 //квалификация, необходимая для успешной установки
},
macos: {
name: "Mac OS",
install_carma: 50
},
linux: {
name: "Linux",
install_carma: 70
}
}
var microsoft = {
system: "windows"
}
var apple = {
system: "macos"
}
Во-первых, поступим как известный итальянский скульптор и отсечём всё лишнее. Получится следующего вида конструкция:
user[ () ? "install" : "cant_install"]();
Сразу видно, что в зависимости от результата некоторого условия вызывается соответствующий метод объекта user. А именно, install в случае, если условие истинно и cant_install, если ложно. Обоим методам передаётся нечто в качестве параметра. Предлагаю разобраться именно с этим нечтом:
os[((user.microsoft_adept ? microsoft : apple).system || "linux")].name;
Нечто — название желаемой операционной системы в зависимости от предпочтений пользователя. Диктую по буквам: если пользователь предпочитает продукты Микрософта, то мы читаем свойство system объекта microsoft. Если нет, то тоже свойство читается у объекта apple. Если такого свойства не существует (вендекапец-там или ещё что-то нехорошее), то пользователю, кроме Линукса ничего не остаётся. Таким образом, мы получаем один из трёх вариантов (см. объектную модель):
os[microsoft.system].name; // т. е. Windows
os[apple.system].name; // т. е. Mac OS
os["linux"].name; // т. е. Linux
В условии, которое определяет вызывать ли метод install или же cant_install у объекта user, мы таким же образом докапываемся до свойства install_carma, в зависимости от пользовательских предпочтений и «ситуации на рынке» и сравниваем значение этого свойства со значением свойства carma и объекта user. Если карма пользователя достаточна, то всё в порядке — вызываем метод user[«install»]. Если же нет, то тоже всё в порядке, но вызываем метод user[«cant_install»] и передаём вызванному в качестве параметра название системы.
Исходный код примера полностью (для копипаста)
var user = {
microsoft_adept: false, //любит ли пользователь продукты Микрософта
carma: 10, //условная квалификация пользователя
install: function(system) { console.log("I'am installing " + system + "!"); },
cant_install: function(system) { console.log("I can't install " + system + "..."); }
}
var os = {
windows: {
name: "Windows",
install_carma: 30 //квалификация, необходимая для успешной установки
},
macos: {
name: "Mac OS",
install_carma: 50
},
linux: {
name: "Linux",
install_carma: 70
}
}
var microsoft = {
system: "windows"
}
var apple = {
system: "macos"
}
user[(os[((user.microsoft_adept ? microsoft : apple).system || "linux")].install_carma <= user.carma) ? "install" : "cant_install"](os[((user.microsoft_adept ? microsoft : apple).system || "linux")].name);
Заключение
Я ещё раз повторюсь, что статья рассчитана в первую очередь на начинающих Javascript-программистов, которым по долгу службы придётся столкнуться с самым разным «чужим кодом», который надо будет читать. Кроме того, ряд примеров нетривиального js-синтаксиса может пригодиться в некоторых случаях, но (sic!) ещё и ещё раз напоминаю, что в статье приведён пример как делать не надо! Старайтесь всегда писать красивый и читабельный код. И я не удержусь от того, чтобы не процитировать известный афоризм: «Пишите код, исходя из того, что все программисты, которые будут сопровождать вашу программу, — склонные к насилию психопаты, знающие, где вы живёте.»