Этот пост является коллективным творчеством.
Всё началось с того, что были обнаружены четыре выходных в ноябре, которые так и просились, чтобы их заняли какой-нибудь поездкой. Вслед за этим были найдены весьма недорогие билеты на самолёт с удобным временем прилёта. И где-то на этом месте было решено, что мы летим в Осло.
Итак, мы купили билеты на Norwegian по 80 евро с человека. Можно было, конечно, немного сэкономить и лететь Ryanair, но в борьбе желания комфорта и жадности победило первое: прилёт в центральный аэропорт всё-таки устраивал нас больше.
Следующий пункт — проживание. Мы прошерстили Booking и airbnb. Цены на жилье пугали, и нас одолевали мысли всё отменить. Я даже обзавёлся аккаунтом на Couchsurfing. Но в итоге сразу после покупки билетов на самолёт я перешёл по ссылке «забронировать ещё и гостиницу» и попал на тот же Booking, который изучал буквально за несколько минут до этого, только цены были значительно ниже. Вероятно, у Norwegian есть какая-то договорённость. В результате отель обошёлся в 160 евро за 3 ночи. Ну что же, всё было готово, оставалось только ждать нужной даты.
Утром 7 ноября мы сели на поезд в Вильнюс, где, как известно, располагается аэропорт Минск-3, до которого добирались на специальной электричке.
Очень удобно. Стоит два с половиной лита, билеты можно купить прямо в поезде, едет семь минут. Только бы ходила почаще.
Лететь до Осло меньше двух часов, в полёте слушали концерт двух младенцев и любовались не столько в иллюминатор, сколько на подбадривающие надписи на сидении спереди и на бумажном пакете.
Хоть мы и прилетели в центральный аэропорт, но он находится в пятидесяти километрах от города. Есть несколько способов оттуда выехать. Мы воспользовались скоростным поездом Flytoget — едет двадцать минут, стоит 170 крон (чуть больше 20 евро, 8 норвежских крон ≈ 1 евро). Можно добраться чуть дешевле на специальном автобусе: билет до города стоит 150 крон, в обе стороны — 250 крон и действует месяц. Идёт он, правда, минут сорок, но конечная у него не на вокзале, как у поезда, а где-то в глубине города. Вот вам, кстати, и преимущество перед Rygge, куда прилетает Ryanair: он находится в шестидесяти километрах от города и транспорта туда ходит значительно меньше.
Сразу на выходе с центрального вокзала нас встречает странная скульптура. Мы всё время, кстати, натыкались на различные скульптуры, странные и не очень. Осло вообще можно смело назвать городом памятников.
Буквально в десяти-пятнадцати минутах пешей прогулки от вокзала находился наш отель. На самом деле он превосходно сочетал в себе черты как отеля, так и хостела. Например, на нижнем этаже помещалась кухня, где вполне можно было приготовить себе ужин. Нам досталась комната на двоих с собственной ванной, но были там и трех-четырехместные апартаменты.
А ещё в нём обнаружилась отличного вида лестница.
Отель расположен в центре, поэтому неудивительно, что мы сразу пошли смотреть город. Правда, было уже темно, поэтому кроме светящегося туалета-куба других фотографий нет.
Вернувшись в отель, мы обнаружили, что лифт прекрасен не менее лестницы.
Утром мы купили Oslo Pass на 48 часов (нам повезло: продавался прямо в отеле) и отправились смотреть музейный полуостров Bygdøy. Кстати, про Oslo Pass: несмотря на цену в 395 крон на человека, он окупился уже в первый день. Без него вход в каждый музей обойдётся в 60-100 крон. Плюс дневной проездной на транспорт 75 крон. Считайте сами.
Итак, Bygdøy (читается Бигдои или Бюгдои или где-то посредине, мы так и не смогли определиться). Как же там красиво!
Тут же на берегу стоит памятник Руалю Амундсену, тому самому покорителю южного полюса, и его команде. В лучах восходящего солнца они стоят, похожие на суррикатов, и смотрят куда-то в даль. Мы тоже решили не отказывать себе в удовольствии понежиться в не по-осеннему тёплых лучах и постоять рядом с такими видными мужами.
Первый музей, в который мы заглянули, был музей Фрама (Frammuseet). Фрам — это название корабля, на котором Амундсен совершал свои экспедиции. И теперь весь немаленький корабль целиком помещён в этот музей. Можно даже заглянуть в каюты и удивиться, как они могли проводить огромное количество времени в настолько ограниченном пространстве.
После музея Фрама мы пошли в музей норвежского мореплавания (Norsk Maritimt Museum). Он располагается прямо напротив Фрама. В этом музее есть небольшой кинозал с панорамным полукруглым экраном, на котором показывают красоты Норвегии, снятые с вертолёта. Сразу захотелось всё это увидеть воочию.
Следующий посещённый — музей Кон-Тики. Я раньше не задумывался, но тут обнаружил, что Тур и Тор — это одно и то же имя (Тур Хейердал пишется как Thor Heyerdahl). Посмотрели на его воссозданный плот и ещё раз удивились, насколько отчаянные были люди, что совершили это путешествие. Вот уж действительно путешествие всей жизни.
К сожалению, сам плот мы не сфотографировали. Но у нас есть другой корабль из этого же музея.
Там же за стеклом можно полюбоваться на Оскар, полученный Хейердалом в 1951 году за лучший документальный фильм.
Хотя от этих трех музеев в глубь полуострова и дальше в город ходит рейсовый автобус, мы решили его не дожидаться, а пройтись пешком до следующего по списку музея кораблей викингов. Следует сказать, что Bygdøy — это не только и не столько музейный, сколько жилой полуостров. Не слишком фешенебельный, но очень милый и определённо весьма живописный район, в котором я с удовольствием поселился бы. Кстати, заметили, что ворота и калитки в частные дома норвежцев по большей части распахнуты, заходи и заезжай.
Музей кораблей викингов (Vikingskipshuset) оказался гораздо более людным местом: там как раз высадилось несколько туристических автобусов. Все хотели посмотреть на несколько кораблей разной степени целости.
А дальше мы собрались и поехали в парк Вигеланда. Вот уж где собрание самых различных скульптур. Как раз тут и можно увидеть того знаменитого злого мальчика.
Тут очень красиво. Несмотря на ноябрь и более северное, нежели у Беларуси, расположение, Норвегия всё ещё в состоянии золотой осени. Многие деревья радуют глаз яркой листвой, трава зеленеет и даже цветут (!) розы. Ну-ка признавайтесь, кто бывал в ноябрьском Ботаническом, — у нас цветут?
Местные здесь просто гуляют с детьми, туристы — изучают необычные скульптурные композиции, являющиеся главной достопримечательностью парка. На его окраине стоит музей скульптора, довольно пустынный во время нашего посещения. Там сейчас выставлены гипсовые этюды и наброски к работам Вигеланда, в том числе и в натуральную величину. Многие из них мы потом увидели в парке в оригинале.
Время близилось к вечеру и трамвай повёз нас в район Акер Брюгге смотреть один из самых красивых закатов. Причал возле ратуши и набережная Акер Брюгге сами по себе очень живописны, летом это место тусовки местной молодёжи, а в золотистом закатном свете всё становится немного сказочным.
Почитав путеводитель, отправились ужинать в Kaffistova. Во-первых, там норвежская кухня, во-вторых, он относится ко второй наценочной категории, а в третьих, для обладателей Oslo Pass там скидка в 20%. Кафе рекомендуем, ко всем предыдущим доводам добавим, что было вкусно. Особенно впечатлил нежный сливочный соус, подаваемый к рыбным блюдам и проходивший у нас под кодовым названием «Смерть диетам».
А ещё в бутылке, крайне похожей на пивную, оказалось не пиво, а солод с сахаром: что-то похожее мы пробовали в музее-пивоварне Heineken. Этот напиток называется Vørterøl, он совершенно без алкоголя и весьма неплох на вкус.
Вернулись в отель, посмотрели шоу Ylvis (тех самых, что поют What Does the Fox Say), ничего не поняли и легли спать. Кстати, обратили внимание на то, что на норвежском телевидении не принято дублировать английский язык, даже перевод англоязычных фильмов идёт в виде субтитров.
Следующий день выдался гораздо более серым. Но это же не повод, чтобы отсиживаться в отеле и игнорировать всё ещё неизвестный город. Осмотр начали с дома парламента. Два раз в день туда водят англоязычные экскурсии, но мы решили не ждать ещё два часа.
Дальше по Karl Johans gate отправились в сторону королевского дворца, попутно осматривая всякие скульптуры и здания.
Королевский дворец больше всего поражает своей охраной, вернее их ритуалами и способом несения службы. Мы довольно долго наблюдали, как они ходят, докладывают обстановку или просто стоят. Какое-то гипнотическое и завораживающее зрелище.
По дороге к ратуше мы встретили ещё одну прекрасную скульптуру.
Сказать, что Ратуша впечатляет, это ничего не сказать. Огромное здание вдоль и поперек разукрашено всевозможными «фресками» с изображением быта норвежцев. В каждом помещении — оригинальный резной потолок, окна в парадных залах выходят на залив. В одной из комнат висит картина Эдварда Мунка «Жизнь», перед которой одну лишь субботу в месяц проводят гражданские церемонии бракосочетания. А ещё, как мы узнали уже дома, именно в Ратуше 10 декабря ежегодно, в годовщину смерти Альфреда Нобеля, происходит торжественная церемония вручения Нобелевской премии мира.
Следующий пункт нашей программы — музей Мунка (Munchmuseet). Оказывается, Эдвард Мунк весьма неплохо овладел классической живописью перед тем, как пуститься во все тяжкие и стать у истоков экспрессионизма. Ну и конечно же мы сфотографировались рядом с одной из четырех версий его знаменитого Крика.
А ещё оставили на память музею мой великолепный портрет.
Но надо спешить, ведь не посещёнными остались два важных архитектурных объекта. Сначала оперный театр. Он действительно большой, красивый, необычный и похож на айсберг, всё как описывают.
Дальше идём мимо фонтана с перчаткой.
И внезапно набредаем на памятник Франклину Рузвельту.
А дальше перед нами крепость Акерсхус (Akershus Festning) и внутри неё замок (Akershus Slott). Красивый старый замок, в котором ещё иногда проводятся всякие торжества и в церкви которого всё ещё проходят службы и справляются обряды.
Уже уходя из крепости заметили человека-подушку. Рядом с ним написано, что этому человеку можно рассказать всё что угодно, поплакаться и что на этой скамейке никто не будет чувствовать себя одиноко.
Настал вечер, и мы отправились ещё в одну кафешку Nilsen Spiseri, отведать по одному из друзей Рудольфа и Вилли.
Там же мы столкнулись ещё с одним норвежским феноменом: так называемым медленным телевидением. Это, например, когда 134 часа в прямом эфире показывают плавание корабля из одного порта в другой. Нам достался менее эпичный вариант, всего 8-ми часовая трансляция горящего камина. Отличный фон для кафе, не то что у нас непонятно что показывают на экранах в заведениях общепита.
Вечерняя прогулка завела нас в толпу серьёзно настроенных людей, которые громко выкрикивали какие-то лозунги. Мы так поняли, что собрались они покричать в защиту животных. Дальше активисты зажгли факелы и двинулись шествием, а полицейская машина расчищала им дорогу. Но мы не стали надолго связываться с этой компанией, а свернули в сторону и оказались на пороге милой церкви (Trefoldighetskirken), двери которой были гостеприимно открыты.
Там же мы встретили работника этой церкви, который нам устроил небольшую экскурсию, даже отвёл на верхнюю галерею, туда, где хоры. Ещё он рассказал, что каждую субботу вечером, как раз когда мы пришли, двери церкви открываются, чтобы накормить ужином и напоить кофе всех желающих, в основном бездомных. Справа от входа за столами группами сидели мужчины и женщины, ели и что-то тихо обсуждали. Интересно, а у нас такое бывает?
Где-то среди всех этих прогулок был поход в магазин за почти традиционными и почти норвежскими свитерами. Но на этом наше путешествие подошло к концу. Утром мы сели на самолёт, который унёс нас обратно в Вильнюс.
Кстати Tax Free возвращается прямо в аэропорту. Девушка за столом просит показать документы из магазина, паспорт, билет на самолёт и собственно вещи. Затем спрашивает, возвращать наличными или на карточку и в какой валюте. Не знаю как на карточку, а наличные отдала прямо тут же.
Хочу ещё упомянуть употребление денег в Норвегии. В путеводителе было указано, что банки обычно берут неплохую комиссию за обмен валюты. Поэтому мы решили не спешить и отложить эту операцию. В результате наличных денег у нас не было всю поездку, да они практически и не были нужны: везде прекрасно обходились банковской карточкой. Единственный раз когда была нужна наличнось, это в музее Мунка. Там камеры хранения с залоговой стоимостью в 10 крон. Но в этом случае нас выручил работник музея, который заранее поинтересовался у нас о наличии этих самых десяти крон, чтобы закрыть ячейку, а потом просто достал из кассы монетку и вручил нам. Ну и ещё раз было неплохо иметь монетку для открытия платного туалета в парке Вигеланда. Но там неподалёку находится музей Вигеланда, так что особых проблем это не доставило.
Путешествие в Норвегию, как и вообще в Скандинавию, — не слишком бюджетное дело. Хотя сэкономить можно. Всем, наверное, известно про каучсерфинг. Если хочется комфорта, ищите отели с включённым в счёт номера завтраком (нам повезло: наш был именно таким). А если в отеле/хостеле ещё и общедоступная кухня есть, то вам повезло: дешевле самому себе готовить, чем питаться в кафе. Конечно, вы не узнаете вкуса Норвегии, не попробуете национальные блюда, но тут уж у кого какая цель. Нам очень понравилась идея с салат-барами в магазинах: там стоят специальные столы (как правило два) с ингридиентами для салата, каждый в своей мисочке. Тут и различное мясо, мелко пошинкованное, и овощи, и макароны, и варёные яйца, и оливки, и ещё много продуктов, из которых можно сварганить салат. Рядом же пластиковые контейнеры, в которые можно наложить то, чего пожелаешь. Стоит это удовольствие 129 крон за килограмм (чуть больше 15 евро). Невероятно удобно для ужина на скорую руку.
Если вы планируете много перемещаться по городу, покупайте проездной на день. Он стоит 75 крон вместо 30-ти за одиночную поездку. Ну или ходите пешком. А если по пути вы ещё собираетесь заглядывать в музеи и прочие достопримечательности — смело покупайте Oslo Pass, в его стоимость включено много плюшек.
Не стоит ездить в Норвегию ради шоппинга: поверьте, тот же Вильнюс в этом плане выгоднее. Нет, в Осло, конечно, европейские цены и тоже бывают распродажи, но в целом оно того не стоит. Не увлекайтесь национальными сувенирами и подарками: свитерами, шапками, шарфиками и так далее. В магазинах средняя цена на такие вещи около 100 евро.
Кстати, если хочется выпить, стоит позаботиться об этом заранее, например, в дьюти-фри для прибывающих в аэропорту. Потому как в самом Осло алкоголь продаётся только в специализированных магазинах Vinmonopolet и стоит довольно дорого. Конечно, в Осло есть и бары, но не могу сказать, какая там будет наценка, мы до бара не дошли.
Ну и наблюдение, не касающееся денег. Большинство норвежцев (по крайней мере столичных жителей) прекрасно владеют английским, нигде у нас не было проблем с объяснением, а словарик норвежского в путеводителе так и не пригодился.
Вильнюс нас встретил длинной очередью на таможенный контроль и свежеотстроенным Duty Free на платформе. Да, алкоголь там весьма недорогой.
Вот и закончились довольно большие выходные. Мы, конечно, увидели лишь небольшую часть Норвегии, но её хватило, чтобы захотеть увидеть ещё. Нужно будет обязательно вернуться в тёплое время года и посмотреть северные районы, фьорды и великолепную природу.
Сегодня у нас отличная бодрая песня из 70-х.
И хотя многие приписывают авторство Ram Jam, на самом деле это не так. История этой песни уходит в XVIII век. Кстати, вот одна из первых известных записей, 1933 год.
Конечно, этот вариант не такой прекрасный, как первый, но это тоже часть истории музыки.
Допустим, у нас есть набор иконок png чёрного цвета с прозрачностью. Как с помощью CSS реализовать возможность изменять цвет иконки произвольным образом? Тут нам на помощь придёт свежий стандарт CSS Masking.
Для достижения результата нужно наложить выбранную иконку в виде маски на фон с нужным цветом. Тогда атрибут прозрачности будет перенесён с иконки на фон.
.icon {
-webkit-mask-image: url(icon.png);
-webkit-mask-size: 100%; /* Масштабируем маску под нужный размер */
background-color: #63b4ec;
}
Небольшая демонстрация. Ну ещё много интересного можно найти на html5rocks.
К сожалению, вся эта красота пока поддерживается только браузерами на основе WebKit, поэтому можно использовать в мобильных приложениях, но следует десять раз подумать перед тем, как включать данные свойства на обычном сайте. Лично для меня оно понадобилось, чтобы добавить растровые иконки к Sencha Touch.
Я знаю, что сегодня не воскресенье, но пройти мимо просто не смог. Боб Дилан наконец выпустил клип на свою песню Like a Rolling Stone. Многие тематические музыкальные издания считают её песней #1 всех времён, но мы не будем столь категоричны, а назовём её просто отличной песней.
Не забываем переключать каналы! Кстати, на 121-м поёт сам Боб Дилан.
Просматривал старые заметки в Evernote и набрел на список паттернов написания кода для JavaScript. Вот они.
Для повышения качества кода и улучшения понимания специфики JavaScript привожу тут весьма вольный перевод первой, не связанной с jQuery, части. Некоторые вещи могут показаться тривиальными, но большая часть программистов почему-то забывает о них, когда они действительно нужны.
Очень надеюсь, что этот пост кому-нибудь пригодится и вы найдёте для себя что-нибудь новое.
1. Объявление функций
Создание анонимных функций и присваивание их переменным.
Плохо
function getData() {
}
Хорошо
var getData = function () {
};
Преимущества:
- Улучшает понимание «функций как объектов».
- Навязывает хорошую привычку ставить точки с запятой.
- Нет навязанного предыдущим опытом представления о функциях и областях видимости.
Именованное функциональное выражение
var getData = function getData () {
};
Преимущества:
- Даёт отладчику определённое имя функции. Это упрощает изучение стека вызовов.
- Позволяет делать рекурсивные вызовы:
getData
может вызывать саму себя по имени.
Недостатки: не работает в IE, и CoffeeScript не понимает подобные выражения (https://github.com/jashkenas/coffee-script/issues/366).
Именованное функциональное выражение + «F»
var getData = function getDataF () {
};
Преимущества:
- Избавление от
(anonymous function)
в стеке вызовов. - Возможность рекурсивного вызова при использовании имя + «F».
- Работает в IE (по крайней мере до тех пор пока нет коллизии имён, как описано здесь: https://github.com/jashkenas/coffee-script/issues/366#issuecomment-242134).
Ссылки
2. Условия
Cпособы использования if-else.
Стандартный способ
if (type === 'foo' || type === 'bar') {
}
Альтернативный способ 1: регулярное выражение
if (/^(foo|bar)$/.test(type)) {
}
Альтернативный способ 2: поиск в объекте
Этот способ будет короче, когда в условии менее пяти элементов.
if (({foo:1, bar:1})[type]) {
}
Альтернативный способ 3: подход как в двоичном поиске
Этот подход лучше применять, когда нужно проверять диапазоны значений.
До:
if (value == 0) {
return result0;
} else if (value == 1) {
return result1;
} else if (value == 2) {
return result2;
} else if (value == 3) {
return result3;
} else if (value == 4) {
return result4;
} else if (value == 5) {
return result5;
} else if (value == 6) {
return result6;
} else if (value == 7) {
return result7;
} else if (value == 8) {
return result8;
} else if (value == 9) {
return result9;
} else {
return result10;
}
После:
if (value < 6) {
if (value < 3) {
if (value == 0) {
return result0;
} else if (value == 1) {
return result1;
} else {
return result2;
}
} else {
if (value == 3) {
return result3;
} else if (value == 4) {
return result4;
} else {
return result5;
}
}
} else {
if (value < 8) {
if (value == 6) {
return result6;
} else {
return result7;
}
} else {
if (value == 8) {
return result8;
} else if (value == 9) {
return result9;
} else {
return result10;
}
}
}
Альтернативный способ 4: Таблицы поиска
Таблицы поиска наиболее полезны, когда есть соответствие между ключом и значением.
До:
if (value == 0) {
return result0;
} else if (value == 1) {
return result1;
} else if (value == 2) {
return result2;
}
После:
// Определяем массив результатов.
var results = [result0, result1, result2];
// Возвращаем правильный результат.
return results[value];
Альтернативный способ 5: только логические операторы
Более короткий способ записи операторов.
var
type = 'foo',
type2 = 'bar',
result = 0;
type == 'foo' && result++;
console.log(result); // 1
!type == 'foo' || result++;
console.log(result); // 2
type == 'foo' && type2 == 'bar' && result++;
console.log(result); // 3
type == 'foo' && type2 == 'bar' && result == 3 && (result=0);
// Скобки нужны, чтобы избежать ошибки с неверной левой частью у присваивания
console.log(result); // 0
type == 'OOF' || result++; // Эквивалентно type != 'OOF' && result++;
console.log(result); // 1
Ссылки
http://paulirish.com/2009/perf/.
Paul Irish отмечает, что первый вариант (стандартный способ) не слишком походит, когда требуется уменьшить размер исходного кода, например, для кода-закладки (bookmarklet). Стандартный способ для небольшого количества условий обычно в цикле работает быстрее, чем регулярное выражение (альтернативный способ 1), и быстрее поиска по объекту (альтернативный способ 2). Скорость выравнивается примерно на десяти условиях. Смотрите http://jsperf.com/if-this-or-that.
3. Доступ к глобальному объекту
Доступ к глобальному объекту без указания идентификатора window
напрямую. Должно работать в ES3, ES5 и ES5-strict.
var global = (function () {
return this || (1, eval)('this');
}());
Тесты: http://jsperf.com/globalx.
4. Одно объявление var
Нужно использовать одно определение var
на функцию.
Преимущества:
- Единственное место в коде, где будут объявлены все локальные переменные, требуемые для функции.
- Защищает от логических ошибок, когда переменная используется до того, как она объявлена.
- Напоминает о том, что нужно объявлять переменные, и таким образом уменьшает количество глобальных переменных.
- Меньше букв (чтобы набирать и передавать).
function func() {
var a = 1
, b = 2
, sum = a + b
, myobject = {}
, i
, j;
// Тело функции...
}
function updateElement() {
var el = document.getElementById("result")
, style = el.style;
// Сделать что-нибудь с el и style...
}
От себя добавлю, что я не пользуюсь этим паттерном. Мне кажется, что современные IDE вроде WebStore могут позаботиться о локальных переменных вместо тебя, главное обращать внимание на их замечания.
5. Hoisting (подъём)
Объявление var
где-либо в функции действует так, как если бы переменные были объявлены в самом верху.
Неправильно:
myname = "global"; // глобальная переменная
function func() {
alert(myname); // "undefined"
var myname = "local";
alert(myname); // "local"
}
func();
Этот кусок кода будет себя вести будто написан так:
myname = "global"; // глобальная переменная
function func() {
var myname; // то же, что и var myname = undefined;
alert(myname); // "undefined"
myname = "local";
alert(myname); // "local"
}
func();
6. Оптимизация циклов for
Стандартный вариант
for (var i = 0; i < myarray.length; i++) {
// сделать что-нибудь с myarray[i]
}
Оптимизация 1
Кешировать размер массива, используя max
.
for (var i = 0, max = myarray.length; i < max; i++) {
// сделать что-нибудь с myarray[i]
}
Оптимизация 2
Использовать только одно объявление var
для соответствия предыдущим советам.
Замечание: недостаток в том, что станет немного сложнее копировать циклы целиком во время рефакторинга.
var i = 0,
max,
myarray = [];
for (i = 0, max = myarray.length; i < max; i++) {
// сделать что-нибудь с myarray[i]
}
Оптимизация 3
Заменить i++
на i = i + 1
или i += 1
, чтобы избежать излишней сложности.
var i = 0,
max,
myarray = [];
for (i = 0, max = myarray.length; i < max; i += 1) {
// сделать что-нибудь с myarray[i]
}
Предпочтительный вариант 1
var i, myarray = [];
for (i = myarray.length; i--;) {
// сделать что-нибудь с myarray[i]
}
Предпочтительный вариант 2
var myarray = [],
i = myarray.length;
while (i--) {
// сделать что-нибудь с myarray[i]
}
7. Оптимизация циклов for-in
Объект:
var man = {
hands:2,
legs:2,
heads:1
};
Где-то в коде был добавлен метод ко всем объектам:
if (typeof Object.prototype.clone === 'undefined') {
Object.prototype.clone = function () {
};
}
Неправильно
Цикл for-in без проверки hasOwnProperty
.
for (var i in man) {
console.log(i, ":", man[i]);
}
Результат в консоли:
hands : 2
legs : 2
heads : 1
clone: function()
Предпочтительный вариант 1
for (var i in man) {
if (man.hasOwnProperty(i)) { // фильтр
console.log(i, ":", man[i]);
}
}
Результат в консоли:
hands : 2
legs : 2
heads : 1
Предпочтительный вариант 2
Преимущество этого варианта в том, что можно избежать коллизий имён, если в объекте man
переопределено свойство hasOwnProperty
.
for (var i in man) {
if (Object.prototype.hasOwnProperty.call(man, i)) { // фильтр
console.log(i, ":", man[i]);
}
}
Предпочтительный вариант 3
Используем локальную переменную, чтобы закешировать Object.prototype.hasOwnProperty
.
var i,
hasOwn = Object.prototype.hasOwnProperty;
for (i in man) {
if (hasOwn.call(man, i)) { // фильтр
console.log(i, ":", man[i]);
}
}
8. (Не) изменение встроенных прототипов
Этот паттерн может сильно навредить поддерживаемости кода, потому что сделает его менее предсказуемым. Но можно сделать исключение, когда следующие условия выполняются:
- Ожидается, что будущие версии ECMAScript или JavaScript добавят эту функциональность. Например, можно добавить методы, описанные в ECMAScript 5, пока не все браузеры реализовали эту функциональность. В этом случае вы просто определяете необходимые методы заранее.
- Вы убеждаетесь, что ваше новое свойство ещё не существует. Ведь оно может являться частью JavaScript-движка в одном из браузеров или, возможно, было уже где-то добавлено в код.
- Вы задокументируете и обсудите с командой это изменение.
if (typeof Object.prototype.myMethod !== "function") {
Object.prototype.myMethod = function () {
// реализация...
};
}
9. switch
Улучшение читаемости и надёжности операторов switch
.
Правила:
- Выравнивайте каждый
case
сswitch
(исключение к правилам отступов после фигурной скобки) - Делайте отступы внутри каждого
case
. - Заканчивайте каждый
case
явнымbreak;
. - Избегайте fall-through (случай, когда вы специально убираете
break
). Если вы совершенно уверены, что fall-through — наилучшее решение, убедитесь, что задокументировали подобные случаи. Они могут выглядеть как ошибки для тех, кто будет читать код впоследствии. - Пишите
default
в концеswitch
, чтобы конструкция возвращала нормальный результат даже если ни один изcase
не сработал.
var inspect_me = 0,
result = '';
switch (inspect_me) {
case 0:
result = "zero";
break;
case 1:
result = "one";
break;
default:
result = "unknown";
}
10. Неявное приведение типов
Нужно избегать неявного приведения типов.
var zero = 0;
Плохо
JavaScript неявно приводит типы переменных, когда сравнивает их. Поэтому сравнения вроде false == 0
или "" == 0
возвращают true
.
if (zero == false) {
// Этот блок выполнится...
}
Хорошо
Чтобы избежать непонятных ситуаций, связанных с неявным приведением типов, всегда используйте операторы ===
и !==
. Эти операторы сравнивают не только значения, но и типы.
if (zero === false) {
// Не выполнится, потому что zero равно 0, а не false
}
Замечание: есть и другое мнение, заключающееся в том, что использование ===
является излишним, когда ==
достаточно. Например, когда вы используете typeof
, вы знаете, что оно возвращает строку, поэтому нет необходимости в стогом сравнении. Однако JSLint требует строгого равенства. Это делает код более последовательным и уменьшает умственное усилие, требуемое для чтения кода: это ==
специально поставили, или забыли поставить ===
.
11. Избегайте eval
Плохо 1
var property = "name";
alert(eval("obj." + property));
Хорошо 1
var property = "name";
alert(obj[property]);
Плохо 2
Важно понимать, что передача строк в setInterval()
, setTimeout()
и конструктор Function()
в большей части схожи с использованием eval
, и, следовательно, нужно этого избегать.
setTimeout("myFunc()", 1000);
setTimeout("myFunc(1, 2, 3)", 1000);
Хорошо 2
setTimeout(myFunc, 1000);
setTimeout(function () {
myFunc(1, 2, 3);
}, 1000);
setTimeout(myFunc, 1000, 1, 2, 3); // в некоторых браузерах (т.е. не в IE)
12. Конвертирование чисел с помощью parseInt
Нужно использовать второй параметр — основание.
Вариант 1
Если опустить в этом примере второй параметр (написать parseInt(year)
), то в результате получится 0. Это потому что «09» предполагает восьмеричное число, как если бы вы выполняли parseInt(year, 8)
, а «09» не является допустимым числом по основанию 8.
var month = "06",
year = "09";
month = parseInt(month, 10);
year = parseInt(year, 10);
Вариант 2
Если вы ожидаете данные вроде «08 hello», то parseInt()
вернёт число, в то время как остальные варианты вернут NaN
.
+"08" // Результат: 8
Number("08") // 8
13. Глобальные переменные
Глобальные переменные — это переменные, объявленные вне всех функций, или просто использованные без объявления.
myglobal = "hello"; // плохо
console.log(myglobal); // "hello"
console.log(window.myglobal); // "hello"
console.log(window["myglobal"]); // "hello"
console.log(this.myglobal); // "hello"
14. Проблемы с глобальными переменными
Плохо 1
function sum(x, y) {
// Неявная глобальная переменная
result = x + y;
return result;
}
Хорошо 1
function sum(x, y) {
// Переменная, объявленная внутри функции, недоступна вне ее.
var result = x + y;
return result;
}
Плохо 2
function foo() {
var a = b = 0;
// ...
}
Этот код будет вести себя так, как если бы вы написали:
var a = (b = 0);
Хорошо 2
function foo() {
var a, b;
// ...
a = b = 0; // обе переменные локальные
}