Маленькие хитрости JavaScript, или пишем скрипты по-новому[5 марта 2004 г.] [обсудить статью в тут]
Вполне возможно, что после этой и следующей наблы вы почувствуете себя глупо. Вы будете ощущать себя так же, как программист для Windows, всю жизнь рисовавший круги, прямоугольники, кнопки и т. д. вручную (по точкам — например, через DirectDraw), и вдруг обнаруживший, что в этой ОС существует куча готовых средств для отрисовки элементов интерфейса.
Признаюсь честно, полгода я сам чувствовал себя точно так же. Началось все с того, что я случайно заглянул в XUL-файлы платформы Mozilla (там хранится код, заведующий некоторыми интерфейсными элементами браузера). Код, который я увидел, выглядел несколько странно и необычно. Это какой вообще язык? Оказалось, что JavaScript, и при том самый обыкновенный. Но я никогда не писал так, и не видел, чтобы кто-то еще это делал!
JavaScript и Perl
Как вы думаете, на какой другой язык программирования больше всего похож JavaScript? Если вы считаете, что это Java или C++, то ошибаетесь. Наиболее близкий к JavaScript язык (по идеологии) — это... Perl. Да-да, вы не ослышались. Perl — ближайший «соратник» JavaScript, и в данной статье я покажу это на примерах.
Прежде, чем заняться сложными вещами, вот вам несколько трюков, которые можно использовать при программировании на JavaScript (и синтаксис которых очень напоминает Perl).
Операторы || и &&
Как и в Perl, в JavaScript можно применять эти полезные операторы не только в логическом контексте, а, например, и в таких случаях:
Листинг 1 скопировать код в буфер обмена
// Значения по умолчанию.
function hello(text) {
alert("Hello, " + (text||"world"));
}
// Не выдает ошибку в случае отсутствия одного из ключей.
// Если же все на месте, присвоит переменной значение
// h['x']['y'], иначе - null.
var element = h && h['x'] && h['x']['y'];
Оператор || возвращает свой второй аргумент, если первый оказался «ложным» (false, null, "", 0), и первый — в противном случае. Оператор && возвращает свой второй аргумент, если первый оказался истинным, и первый — если ложным.
К сожалению, оператор ||=, столь популярный в Perl, в JavaScript не поддерживается.
Хэши
Возможно, вы слышали, что любая переменная в JavaScript — это на самом деле объект. Не важно, число это или строка. Например, можно написать:
Листинг 2 скопировать код в буфер обмена
var part = "Matrix has you".substr(0, 6);
var a = 10;
var b = a.toString(); // конечно, это 10
alert(typeof 10); // выводит "Number"
Но что представляет собой объект? Как ни странно, любой объект выглядит в программе как хэш. Да-да, тот самый хэш, который есть и в языке Perl. И создается он точно таким же оператором, только вместо => используется двоеточие:
Листинг 3 скопировать код в буфер обмена
var hash = {
color: "red",
artefact: "pill",
actors: {
supplier: "Morpheus",
consumer: "Neo"
}
}
Обратите внимание на две вещи. Во-первых, ставить ; в конце не обязательно: в JavaScript точка с запятой — вообще необязательный символ, вместо нее может служить и конец строки. Во-вторых, лишние запятые после } не допускаются (в отличие от C++, Perl, PHP).
Свойства (и методы, кстати, тоже) объекта — это просто элементы хэша. Для обращения к ним можно использовать две разновидности синтаксиса:
Листинг 4 скопировать код в буфер обмена
var element1 = hash.element;
var element2 = hash['element'];
А вот теперь — внимание: эти два способа полностью идентичны! Нет никакой разницы, обращаетесь ли вы к хэшу как hash.element или как hash['element']. Зачем же тогда нужен второй вариант? Нетрудно догадаться: мы можем не знать в явном виде имя ключа, к которому хотим обратиться:
Листинг 5 скопировать код в буфер обмена
var key = "element";
var element1 = hash.key; // полная ерунда
var element2 = hash[key]; // а вот так - правильно
Хэши можно создавать и поэлементно:
Листинг 6 скопировать код в буфер обмена
var hash = new Object(); // Object - это и есть хэш.
hash.color = "blue";
hash.element = "pill";
Ключи хэша, конечно, могут представлять из себя и обычное число:
Листинг 7 скопировать код в буфер обмена
var hash = {
10: 'input x',
20: 'print "Hello, ", x'
}
alert(hash[10]);
Тем не менее, выражение hash.0 вместо hash[0] не работает (хотя IE иногда имеет обыкновение показывать такие сообщения об ошибке:
Массивы
Последние примеры наводят на правильную догадку о природе массивов в JavaScript. Да, действительно, массивы — это обыкновенные хэши с числовыми ключами, а также ключом length, содержащим их длину.
На самом деле это не совсем так, потому что команды for (var k in arr) alert(k) выводят лишь числовые ключи массива, но не свойство length. Тем не менее, в первом приближении гипотезу о происхождении массивов вполне можно принять.
Массивы в JavaScript создаются оператором [] (заметьте, опять аналогия с Perl):
Листинг 8 скопировать код в буфер обмена
var arr = [100, 200, 300];
for (var k in arr) alert(k + "=>" + arr[k]);
alert("length: "+arr.length);
Распечатка
Если попытаться распечатать весь массив командой alert(arr), то будут отображены все его элементы. Это достаточно удобный трюк, если в отладочных целях надо вывести значения нескольких переменных, но лень писать плюсики и запятые в кавычках:
Листинг 9 скопировать код в буфер обмена
// Можно и так...
alert(status+","+location+","+navigator.appName);
// Но следующий код смотрится явно лучше:
alert([status, location, navigator.appName]);
Команда вроде alert([1,2,[4,5],6]), как это ни печально, выводит все элементы массива в кучу, не обращая внимания на вложенность.
К сожалению, распечатать хэш таким способом не получится: будет выведена строка [object Object] (точный вид зависит от браузера). Для того, чтобы все-таки отлаживать программы со сложными хэшами, я написал следующую функцию:
Листинг 10 скопировать код в буфер обмена
function Dump(d,l) {
if (l == null) l = 1;
var s = '';
if (typeof(d) == "object") {
s += typeof(d) + " {\n";
for (var k in d) {
for (var i=0; i<l; i++) s += " ";
s += k+": " + Dump(d[k],l+1);
}
for (var i=0; i<l-1; i++) s += " ";
s += "}\n"
} else {
s += "" + d + "\n";
}
return s;
}