Внутренняя работа присущих JavaScript объектов: строк, чисел и массивов.

До сих пор мы рассматривали языковые конструкции JavaScript: операторы if, циклы, функции и т.д. В этой лекции будет рассмотрена внутренняя работа некоторых присущих JavaScript объектов: строк, чисел и массивов.

В JavaScript строка является любым фрагментом текста. Как и многие другие объекты в JavaScript, строки можно определять несколькими различными способами:

var myString = 'Hello, World!';

var myString = new String('Hello, World!');

Первый метод используется наиболее часто. Второй метод применяется редко и только для гарантии, что получаемый объект является строкой. Например:

var n = 5;

var s = new String(n*20);

В этом примере s будет строкой "100". Если просто задать s как n*20, то s будет содержать число 100. Однако поскольку JavaScript является слабо типизированным языком, то эти различия не будут существенно влиять на то, что вы делаете.

Строковые объекты (var n = new String('Hello World')) технически являются в Internet Explorer более медленными при некоторых операциях, чем строковые литералы (var n = 'Hello World'). Однако это поведение совершенно противоположно в других браузерах. В любом браузере различие редко бывает настолько заметно, чтобы об этом беспокоиться.

Единственное важное различие состоит в том, что eval() не работает со строковыми объектами.

Что, если в строке имеется апостроф? Следующий код работать не будет:

var n = 'The dog took it's bone outside';

Легко видеть, что апостроф в "it's" заканчивает строку. Поэтому мы получаем строку "The dog took it", за которой следует "s bone outside'". Это продолжение само по себе не является допустимым кодом JavaScript (или правильным грамматически, если на то пошло), поэтому будет получена ошибка.

Здесь можно сделать две вещи. Так как строка определяется с помощью одиночных или двойных кавычек, то можно задать строку с помощью двойных кавычек. Другая возможность состоит в экранировании апострофа. Чтобы экранировать символ, необходимо просто подставить перед ним символ \. Символ \ в этом контексте сообщает JavaScript, что следующий символ необходимо воспринимать в точности так, как он есть, в номинальном значении, а не как специальный символ.

var n = "The dog took it's bone outside";

var n = 'The dog took it\'s bone outside';

Если в строке должен присутствовать символ \, то он экранируется таким же образом: '\\'.

В предыдущей лекции мы встречались с функциями indexOf и lastIndexOf. Напомним, что они делают. Функция indexOf возвращает число, определяющее первую позицию одной строки в другой. Если разыскиваемая строка не существует, то indexOf возвращает – 1. Функция lastIndexOf идентична indexOf, но возвращает не первую позицию вхождения строки, а последнюю.

Тот факт, что функции indexOf и lastIndexOf возвращают – 1, если строка не существует, является очень полезным и позволяет использовать эти функции для достаточно распространенной задачи – проверки того, что одна строка существует внутри другой.

Существует несколько других полезных функций для работы со строками, которые мы перечислим и кратко поясним.

[x] charAt() сообщает, какой символ находится в определенной позиции строки. Поэтому 'Test'.charAt(1) = 'e'.

[x] length сообщает длину строки . 'Test'.length = 4.

[x] substring() выдает строку между двумя индексами. 'Test'.substring(1, 2) = 'e'.

[x] substr() аналогична substring(), только второе число является не индексом, а длиной возвращаемой строки. Если это число указывает на позицию за пределами строки, то substr() вернет существующую часть строки. 'Test'.substr(1, 2) = 'es';

[x] toLowerCase() и toUpperCase() делают то, что обозначают: преобразуют строку в нижний или верхний регистр символов соответственно. 'Test'.toUpperCase() = 'TEST';

Примеры всех приведенных выше функций:

alert('This is a Test'.indexOf('T')); // 0

alert('This is a Test'.lastIndexOf('T')); // 10

alert('This is a Test'.charAt(5)); // i

alert('This is a Test'.length); // 14

alert('This is a Test'.substring(5, 9)); // is a

alert('This is a Test'.substr(5, 9)); // is a Test

alert('This is a Test'.toUpperCase()); // THIS IS A TEST

alert('This is a Test'.toLowerCase()); // this is a test

Последней строковой функцией, которая будет рассмотрена, является eval(). eval() получает строку и выполняет строку, как если бы это был код JavaScript.

eval("alert('Hello, World!')");

В этом примере будет выведено сообщение "Hello, World!", как если бы функция alert была написана обычным образом. Это может быть очень полезно, так как позволяет создать содержащую код строку, а затем ее выполнить.

Работа с числами в JavaScript происходит достаточно просто. В лекциях 1 и 2 было показано, как выполняются базовые арифметические операции, операторы ++ , – -, а также *=, +=, /= и – =. Мы узнали, что NaN означает "Не число" и что делает функция isNaN(). Осталось рассмотреть еще только несколько вещей.

Объект Math в JavaScript содержит функции, позволяющие сделать почти все, что можно сделать с числами помимо обычной арифметики. Math.PI, например, содержит просто число 3.141592653589793. В нем содержатся тригонометрические функции (sin, cos, tan, и т.д.), функции для округления чисел (Math.floor возвращает число, округленное с недостатком, Math.ceil возвращает число, округленное с избытком, а Math.round округляет число "нормально") и многие другие. Существует очень много функций, объяснять которые здесь не имеет смысла. Их всегда можно найти в подходящем справочнике. (Например, )

Двумя наиболее распространенными задачами, связанными с числами, являются преобразование числа в строку и строки в число. Как уже говорилось, JavaScript является слабо типизированным языком, а это означает, что типы данных не имеют большого значения, но существуют некоторые случаи, когда надо быть уверенным, что имеется число или строка. Если надо сложить, например, 5 и число, которое вводит пользователь, то надо быть уверенным, что введено число, а не слово "Привет".

var n = parseInt("3.14"); // 3

var n = parseFloat("3.14") // 3.14

Функция parseInt возвращает целое значение своего аргумента. Аргументы "3.14", "3", "3.00001" и "3.9999" превратятся в значение 3. Функция parseFloat, с другой стороны, возвращает также любое десятичное значение. Обе эти функции пытаются "очистить" данные перед возвращением числа. Например, parseInt("3a") вернет значение 3.

Существует также несколько методов, которые можно использовать, когда надо преобразовать число в строку:

var n = 5;

var m = n.toString();

var m = n+'';

var m = new String(n);

Как говорилось ранее, последний метод может быть немного непривычным, поэтому предполагается, что пользователь будет держаться от него в стороне, если только не понадобится использовать объект String для специальных целей. Предпочтительным методом является n.toString(), но необходимо отметить, что часто используется второй метод. Например, если имеется уведомление alert('Имеется' + apples + 'яблок'), то число apples автоматически преобразуется в строку.

Если необходимо выполнить строковую операцию с переменной, то необходимо быть уверенным, что имеется строка. Если, например, имеется запись года из 4 цифр и ее надо преобразовать в 2 цифры:

var year = 2000;

var sYear = year.toString();

var year2 = sYear.substr(sYear.length-2);

Можно было бы также легко вычесть 2000 из этой даты, но что, если датой является 1995? или 1800? или 2700 или просто 5? В результате могли бы получиться совершенно неправильные даты, если вычесть 2000 из каждой такой даты. Используемый метод всегда даст правильные две цифры года.

Массив является по сути списком элементов. Каждый элемент массива может быть чем угодно, но обычно они связаны друг с другом. Если, например, необходимо отследить 30 студентов класса, то можно создать массив студентов:

var students = new Array();

students[0] = 'Sam';

students[1] = 'Joe';

students[2] = 'Sue';

students[3] = 'Beth';

Как можно видеть, определить массив очень просто, так же, как и присвоить значения его элементам. Однако пример выше имеет слишком много кода для относительно небольшого результата. Нет ничего удивительного в том, что существует несколько методов для создания массива. Значительно более компактным будет следующий пример:

var students = ['Sam', 'Joe', 'Sue', 'Beth'];

Это код создает точно такой же массив, что и предыдущий пример, но, как можно видеть, он значительно более компактный и ничуть не сложнее для понимания. Скобки ([ и ]) в этом примере сообщают коду, что будет создан массив. Простая запись var students = []; является тем же самым, что и запись var students = new Array();. Правда, некоторые люди считают, что использование слова Array более наглядно, чем запись [], поэтому можно использовать любой метод записи.

Что можно теперь сделать с этим массивом студентов? Чтобы обратиться к любому элементу массива, необходимо знать его индекс. В первом примере можно видеть, что в скобках находятся числа (0-3). Это индексы. Если требуется узнать имя третьего студента, то надо будет написать alert(students[2]);. Почему 2, а не 3? Массивы в JavaScript начинают индексацию с 0, а не с 1. Поэтому первым элементом в нашем массиве будет students[0], вторым – students[1], сотым – students[99], и т.д. Для этого не существует никакой реальной причины, просто так устроен JavaScript и многие другие языки программирования. Некоторые другие языки используют в качестве первого индекса 1.

Наиболее распространенной задачей при работе с массивами, помимо изменения его данных, является проверка его длины, обычно для того, чтобы можно было перебрать весь массив и выполнить некоторую задачу с каждым элементом.

var students = ['Sam', 'Joe', 'Sue', 'Beth'];

var suffixes = ['1st', '2nd', '3rd', '4th'];

for(var i=0; i

alert(suffixes[i]+' студент -- '+students[i]);

}

Важный момент, который необходимо знать о массивах, состоит в том, что каждый элемент массива может содержать любой произвольный объект. В этих примерах каждый элемент массива является строкой, но они могут быть также числами, объектами, функциями, даже другими массивами. Электронная таблица (такая, как Excel) является хорошим примером массива, содержащего другие массивы. Прежде всего имеется массив столбцов. Каждый столбец будет в свою очередь содержать в себе массив строк. Этот массив создается точно таким же образом, как и массив students:

var spreadsheet = [

['A1', 'B1', 'C1', 'D1'],

['A2', 'B2', 'C2', 'D2'],

['A3', 'B3', 'C3', 'D3'],

['A4', 'B4', 'C4', 'D4']

];

Переносы строк в JavaScript обычно не имеют значения. В этом примере переносы строк используются для придания коду большей наглядности и не влияют на код никаким образом.

Можно видеть, что здесь имеется 5 массивов. Четыре внутренних массива (или вложенных массива) содержатся в одном большом массиве, spreadsheet. Если потребуется узнать значение на пересечении второго столбца и третьей строки, то можно написать:

var col2 = spreadsheet[1];

alert(col2[2]);

// или

alert(spreadsheet[1][2]);

Оба фрагмента кода делают одно и то же, выводят значение "C2".

Существует несколько распространенных операций, которые выполняются с массивами. Первой является добавление элемента в конец массива. Вернемся к массиву students, который содержит в данный момент 4 элемента. Чтобы добавить новый элемент, надо просто задать значение для 5-го элемента:

var students = ['Sam', 'Joe', 'Sue', 'Beth'];

students[4] = 'Mike';

students[students.length] = 'Sarah';

students.push('Steve');

// теперь массив содержит 7 элементов: ['Sam', 'Joe', 'Sue', 'Beth', 'Mike', 'Sarah', 'Steve']

Здесь также существует несколько способов для выполнения этой задачи. Первый метод, students[4], используется редко, так как обычно неизвестно заранее в точности, сколько будет элементов. Поэтому применяется один из двух оставшихся методов. push является функцией, которая просто добавляет то, что получает, в конец массива, как и предыдущий метод, использующий свойство .length.

Не так часто, но иногда необходимо также удалить объект из массива. В этом случае задействуется функция splice, которая позволяет добавить или удалить любое количество элементов массива, но в данный момент мы собираемся использовать ее для удаления одного студента, Mike, который переехал в другой город:

var students = ['Sam', 'Joe', 'Sue', 'Beth', 'Mike', 'Sarah', 'Steve'];

students.splice(4, 1);

Splice в этом примере получает два аргумента: начальный индекс и число элементов для удаления. Так как Mike является пятым студентом, то его индекс будет 4. Будет удален только 1 студент, поэтому здесь используется 1. В результате имеем массив с удаленным Mike:

['Sam', 'Joe', 'Sue', 'Beth', 'Sarah', 'Steve'];

Чаще всего точно неизвестно, где в массиве находится элемент. К сожалению, единственным способом выяснить это является перебор всех элементов массива. Можно написать небольшой простой сценарий, который позволит легко добавлять или удалять студентов:

var students = ['Sam', 'Joe', 'Sue', 'Beth'];

function addStudent(name){

students.push(name);

}

function removeStudent(name){

for(var i=0; i

if(students[i].toLowerCase() == toLowerCase(name)){

students.splice(i, 1);

break;

}

}

}

Имя студента:

Добавить этого студента

Удалить этого студента

Студенты:

Единственным новым моментом здесь является слово break. break останавливает выполнение кода любого цикла, в котором находится: цикла for, цикла do или switch. Поэтому в данном случае, когда удаляемый студент найден, мы прерываем цикл for, так как выполнили свою задачу.

Часто бывает необходимо преобразовать массив в строку или строку в массив. Имеется две функции, которые могут легко это сделать: join и split. Функция join получает массив и преобразует его в строку с помощью разделителя, заданного в join. Функция split действует в обратном направлении и делает массив из строки, определяя новый элемент c помощью разделителя, заданного в split:

var myString = 'apples are good for your health';

var myArray = myString.split('a');

// строка myString разбивается на элементы на каждом найденном символе 'a'.

alert(myArray.join(', '));

// преобразуем myArray снова в строку с помощью запятой,

// так что можно видеть каждый элемент

alert(myArray.join('a'));

// теперь преобразуем myArray снова в строку с помощью символа 'a',

// так что снова получается исходная строка

Еще две полезные функции для работы с массивами – pop и shift. Функция pop удаляет последний элемент из массива и возвращает его. Функция shift удаляет первый элемент из массива и возвращает его.

var students = ['Sam', 'Joe', 'Sue', 'Beth'];

while(students.length>0){

alert(students.pop());

}

К сожалению, при этом массив был уничтожен: он теперь пуст. Иногда именно это и надо сделать. Если требуется просто очистить массив, то проще всего задать его длину (length) равной 0:

students.length = 0

Теперь массив пуст. Даже если снова задать длину массива больше 0, все данные в массиве уже будут уничтожены.

Все использованные до сих пор массивы называются "индексными массивами", так как каждый элемент массива имеет индекс, который необходимо использовать для доступа к элементу. Существуют также "ассоциативные массивы", в которых каждый элемент массива ассоциирован с именем в противоположность индексу:

var grades = [];

grades['Sam'] = 90;

grades['Joe'] = 85;

grades['Sue'] = 94;

grades['Beth'] = 82;

Ассоциативные массивы действуют немного иначе, чем индексные. Прежде всего, длина массива в этом примере будет равна 0. Как же узнать, какие элементы находятся в массиве? Единственный способ сделать это – использовать цикл "for-in ":

for(student in grades){

alert("Оценка" + student + "будет:" + grades[student]);

}

Синтаксис цикла for-in следующий: "for(item in object){". Цикл пройдет через все элементы в объекте, и элемент будет именем элемента. В данном случае элементом является "Sam", затем "Joe", "Sue" и "Beth".

Последнее замечание о массивах состоит в том, что в действительности можно объединять ассоциативные и индексные массивы, хотя это обычно не рекомендуется, так как может вызывать некоторые проблемы. При правильном использовании, однако, можно с успехом это применять.

var students = ['Sam', 'Joe', 'Sue', 'Beth'];

students['Sam'] = 90;

students['Joe'] = 85;

students['Sue'] = 94;

students['Beth'] = 82;

alert('Всего имеется '+(students.length)+' студентов: '+students.join(', '));

for(var i=0; i

alert("Оценка" +students[i]+"будет: "+students[students[i]]);

}

Хотя это может показаться немного сложным, здесь нет ничего такого, о чем не говорилось в этой лекции.

Теперь читатель должен достаточно хорошо понимать основные типы данных JavaScript: строки, числа и массивы. В следующей лекции будет рассмотрена Объектная модель документа, или DOM (Document Object Model).