Этот html-файл, используя объект document (текущий в браузере)
и его метод write, пишет на экране текст. Далее идут два отладочных способа вывода.
Скрипт выполняется сразу при открытии документа, после его write, идёт вывод содержания тела head.
<html>
<head>
<meta charset="utf-8">
<title>Example</title>
<script type="application/javascript">
document.write("<h1>Hello!</h1>"); // выводит на странице
alert("Hello"); // выскакивающее окошко
console.log("Hello"); // в консоль отладчика
</script>
</head>
<body>
</body>
</html>
Не обязательно скрипт <script>...</script> описывать в заголовочном разделе <head>.
Это можно делать и внутри <body>, непосредственно в том месте, где он используется
(например, рядом с канвасом).
Вместо write можно использовать writeln, что удобно делать внутри моноширинного тега pre:
document.writeln("<pre>");
document.writeln("line1", "тамже ещё текст");
document.writeln("line2 (новая)");
document.writeln("</pre>");
Скрипт можно оформить как функцию и запусть её из тега body (при этом document.write(...) затрёт всё что идёт в body):
<html>
<head>
<script type="application/javascript">
functionrun()
{
document.write("<h1>Hello!</h1>");
}
</script>
</head>
<body onload="run();">
</body>
</html>
Скрипт можно писать в отдельном файле, например hello.js
и подключать в заголовке head следующим образом (тегов script может быть произвольное число):
Наконец, скрипты могут вставляться непосредственно в элементы html-разметки.
Например, чтобы написать случайное число: 0.42446841058081963
надо в тексте html написать:
Если в Chrome возникли проблемы с загрузкой изображений или других файлов непосредственно с диска
добавь флаги безопасности в командной строке:
chrome.exe --disable-web-security
Базовый синтаксис
JavaScript является объектно-ориентированным языком с динамической типизацией и автоматическим приведением типов.
Все идентификаторы регистрозависимы, могут начинаться с нижнего подчеркивания (_) или знака доллара ($).
varx = 5; // переменные стоит объявлять
y = 4; // можно и не объявлять, тогда они становятся глобальными
alert( x+y ); // => 9 интерпретируются как целые
x = "3";
alert( x+y ); // => 34 а это уже строка
alert( typeof(x) ); // => string
alert( typeof(Infinity) ); // максимальное вещественное число => number
alert( 1/0 ); // деление на ноль => Infinity
alert( 2*"a"); // => NaN
alert( 2*"2"); // => 4 (строка "2" преобразовалась в число)
Infinity и NaN две зарезервированных числовых константы. Первая может быть результатом операций и дальше участвовать в вычислениях: 2*Infinity==Infinity. Вторая возникает при недопустимых операциях: Infinity-Infinity, 2*"a". Функция isFinite(x) возвращает true если число не равно Infinity.
Переменная будет иметь тип undefined даже если она объявлена (var z;), но ей не было присвоено значение.
Переменные лучше всегда объявлять (включая индексы в циклах). Иначе, став глобальными они могут непредсказуемо изменятся, особенно при вызове функции внутри цикла, которая сама используе циклы с тем же индексом.
Можно сослаться на переменную, которая объявляется позже.
Объявленные (var) переменные имеют локальную видимость только внутри функций, но не внутри остальных блоков {...}. Например, для if(true){ var x=5; } переменная x будет видна ниже.
Отладчик браузера будет ругаться на необъявленные переменные, если в каждом сткрипте поставить директиву:
'use strict';
В этом случае можно импользовать объявления:
varx; // Переменная локальна внутри функции, но не блока (инициализация необязательна).
let y; // Локальная переменная в области видимости блока (инициализация необязательна).
const z; // Именованная константа, доступную только для чтения.
Основные операторы имеют C-побный синтаксис. Например:
if(a==1) res=1; elseres=2;
switch(a) {
case1: res=1; break;
case2: res=2; break;
default: res=0; break;
}
while(i < 10) { i++; }
do{ i++; } while(i < 10)
for(vari = 0; i < 100; i++) a[i]=i;
Дополнительно существует цикл по перечислению всех элементов массива или структуры:
vararr = [1, 2, 3];
for(vari ina)
a[i]=2*i;
varobj = { k1: 137, k2: "Hi!", "k3": [1, 2]};
for(vari inobj)
alert('key is: '+ i + ', value is: '+ obj[i]);
Действуют стандартные С-операторы:
Arithmetic operators: +, -, *, /, %
Increment operators: ++ and -- (префиксные и постфиксные)
Есть два логических сравнения: == - совпадение значения, === - совпадение и значения и типа.
При == а операнды сперва преобразуются в примитивы, затем приводятся к одному типу, и только после этого сравниваются. Поэтому для выяснения
неопределённости переменнной быстрее будет x===undefined.
Существует два типа структур: массив (пронумерованный набор значений в [...]) и хеш (набор пар “имя/значение” в {...}).
Они имеют тип object.
Работа с массивом:
vararr = newArray("aaa", "bbb", "ccc");// задание элементов
arr[arr.length-1] = "CCC"; // доступ к последнему элементу
for(vari=0; i < arr.length; i++)
arr[i] = i; // перебор всех элементов массива
Добавлять новые элементы можно, присваивая в не существующий индекс:
vara = [1, 2];
a[5]=3;
alert(a.length); // => 6
alert(a[4]); // => undefined (промежуточное значение не определено)
deletea[1]; // теперь a[1] undefined
Массив как список или стек:
a.push(5, 6, 7); // добавляет в конец массива, возвращая новую длину
a.unshift(1,2,3); // тоже, что push, но в начало массива (медленее!)
x=a.pop(); // Удаляет последний элемент и возвращает его
x=a.shift(); // Удаляет первый элемент и возвращает его (медленнее!)
// length после pop, shift уменьшается на 1
arr = a.slice(start_index, end_index); // получить кусок массива
arr = a.splice(start, deleteCount); // удалить deleteCount элементов, начиная с индекса start.
arr = a.splice(start, n_del, i1, i2,...);// удалить n_del штук, начиная с start и вставить там i1,...
Манипуляции с массивами
vara=[3, 5, 6], b=[1, 2, 3];
vara = a.reverse(); // в обратном порядке => 6, 5, 3
c=a.concat(b); // объединение 2-х массивов => 6,5,3,1,2,3
c=c.sort(); // сортировка => 1,2,3,3,5,6
arr = [1,-1, 0];
a = arr.sort() // => arr = [ -1, 0, 1 ]
alert(a === arr) // => true, это тот же, но отсортированный массив!
varst = [1,2,3].join(); // => "1,2,3" (превращение массива в строку)
varst = [1,2,3].join("|"); // => "1|2|3" (превращение массива в строку с разделителем)
Сортировка с функцией сравнения:
arr.sort( sortFunction );
functionsortFunction(a, b)
{
if(a меньше, чем b по некоторому критерию) return-1;
if(a больше, чем b по некоторому критерию) return1;
return0; // в случае а = b вернуть 0
}
Массив – это объект, где в качестве ключей выбраны цифры, с дополнительными методами и свойством length.
Так как это объект, то в функцию он передаётся по ссылке и в него можно присваивать любые свойства
(но это может понизить эффективность):
varfruits = []; // создать массив
fruits[0] = 5; // присвоить свойство с любым номером
Методы push/pop выполняются быстро, а shift/unshift – медленно.
Не используйте for..in для массивов, так как он выведет все свойства объекта, а не только цифровые.
Кроме этого, цикл for (var i=0; i<arr.length; i++) в браузерах выполняется в 10-100 раз быстрее.
Длина length – не количество элементов массива, а последний индекс + 1
При уменьшении length массив укорачивается (процесс необратимый).
Самый простой способ очистить массив – это написать arr.length=0;
Если элементы массива нумеруются с большими пропусками, то стоит использовать обычный объект. Массивы предназначены для работы с непрерывной упорядоченной коллекцией элементов.
Браузеры стараются хранить массивы в памяти не в виде хэш-таблицы, а в виде непрерывной области памяти.
Ассоциативные массивы (хеши)
Работа с хешами (имена ключей могут быть и строками):
varobj = {
k1: 137,
k2: "Hi!",
"k3": [1, 2],
7: { a: 5}, // obj[7] или obj["7"], но не obj.7
};
obj.k2="By"; // доступ к свойствам
obj["k2"] = "By"; // тоже самое
for(vari inobj) // вывод всех ключей и полей
alert('key is: '+ i + ', value is: '+ obj[i]);
varobj = { }; // пустой объект
obj.k1 = 137; // свойства можно добавлять "налету"
Хеши могут быть объектами (их поля - другие объекты и функции). Внутри функции доступ к полям объекта осуществляется при помощи переменной this (т.е. "this object").
varobj = {
v : 137,
p : {x:1, y:1},
get: function(){ returnthis.v; }
};
varx = obj.p.x;
x=obj.get();
varst=obj.toString(); // string representation of the object
Функции
Functions in JavaScript are actually data. This means that the following two ways to define a function are exactly the same. Имена функций можно присваивать в переменные:
functionf(){return1;}
varf = function(){return1;} // typeof f => "function"
Две функции с одинаковым именем не имеют смысла, т.к. вторая переопределит первую. Полиморфизм функций (разное число аргументов) делается так:
functionargs() { returnarguments; } // любая функция знает массив всех своих аргументов
Локальные переменные являются локальными независимо от того где они внутри функции объявлены (inside the function the local scope is more important than the global scope):
vara = 123;
functionf() {
alert(a); // => undefined, а не 123!
vara = 1;
alert(a); // => 1
}
f();
Объекты в JS всегда передаются по ссылке, а простые типы, по значению.
Единственный способ передать простой тип-сделать из него объект:
varb1 = newBall(5); // создание при помощи new нового объекта
b1.radius=10;
varb2 = newb1.constructor(7); // имя конструктора constructor:
if(b2 instanceofBall){ } // проверка от какого конструктора создан объект
When you copy an object or pass it to a function, you only pass a reference to that object. Consequently, if you make a change to the reference, you are actually modifying the original object. The same thing applies when passing objects to functions. Тоже самое относится к массивам. Но не к строкам и числам!
Наследование:
varClass = function() // функция-конструктор класса
{
this.className = 'Class';
alert("Class");
}
Class.prototype.method = function() // описываем открытый метод класса
SubClass.prototype= newClass(); // объект надкласса в .prototype подкласса сразу под конструктором
SubClass.prototype.method = function() // переопределяем унаследованный метод надкласса
{
alert('method of '+ this.className + ' but new one');
}
varsubc = newSubClass(); // создаем экземпляр класса SubClass
subc.method(); // выводит 'method of SubClass'
Строки
Содержимое строки в JavaScript нельзя изменять. Нельзя взять символ посередине и заменить его. Как только строка создана – она такая навсегда.
Можно лишь создать целиком новую строку и присвоить в переменную вместо старой:
Если строки окружаются двойными ковычками " ", то в них можно использовать одинарные '. И наоборот.
В строке можно использовать "escape character" для \", \',
\\ (backslash),
\n" (new line), \t" (tab) и т.д.
Строку можно создавить при помощи new, но это уже будет объект, поэтому при точном сравнении получится false:
vars1 = "box"
vars2 = newString("box");
s1 === s2; // false because s1 - string and s2 - object
s1 == s2; // true - произойдёт преобразование типов
Нельзя сравнивать и два объекта, потому, что объекты в JS нельзя сравнивать.
Методы объекта строка:
s.length; // число символов в строке
s.charAt(n) // символ на n-той позиции; тоже что s[n]
s.charCodeAt(n) // код unicode of the character на n-той позиции
Accessing a String as an Array (т.е. при помощи []) is unsafe and unpredictable
(it does not work in all browsers). If you want to read a string as an array, convert it to an array first:
s=s.split(""); (разбивает на символы).
s.substr(n, cnt) // возвращает подстроку c n-го символа и cnt штук символов в строке.
s.substring(n1,n2) // возвращает подстроку начиная с n1 и до (но не включая) n2
s.slice(n1,n2); // тоже, но n1,n2 могут быть < 0 (тогда отчсёт с конца строки)
s.slice(n); // вся строка, начиная с n-того символа или с конца по начало, если n < 0
s = s.replace("a","b"); // заменяет первую подстроку "a" на "b", см. регулярные выражения.
s = s.replace(/a/g,"b");// заменяет все подстроки "a" на "b", см. регулярные выражения.
s = s.toLowerCase(); // возвращает строковое значение с символами в нижнем регистре.
s = s.toUpperCase(); // возвращает строковое значение с символами в верхнем регистре.
'абв'.repeat(2); // 'абвабв'
s.includes('ox'); // есть ли подстрока
s.startsWith('bo'); // начинается ли строка подстрокой (true)
s.endsWith('ox'); // заканчивается ли строка подстрокой (true) или -1, если нет
s.search('bo'); // индекс первого вхождения подстроки, или -1, если нет
s.indexOf('bo'); // тоже самое, но не позволяет исппользовать регулярные выражения (ниже)
s.indexOf('bo', 5); // тоже, начиная с 5-того места
s.lastIndexOf('bo');// индекс последнего вхождения подстроки или -1, если нет
s.trim(); // обрезает пробельные символы в начале и в конце строки (ECMAScript 5).
st = JSON.stringify(lst); // => {"name":"Mary","ph Num":[2342432,56433]}
st = JSON.stringify(lst, null,' '); // перевод коретки и пробел перед каждым элементом
arr = JSON.parse('[1, 5, "false"]'); // => [1, 5, "false"] из строки в объект
Регулярные выражения
Регулярное выражение берётся в скобки /рег_выраж/ или создаётся как объект (если надо специфично сформировать):
varv = "word";
varre = newRegExp("[ ~#]"+v+" "); // это тоже, что var reg = /[ ~#]word\s/;
vark = txt.search( re );
varre = /ab+c/i; // эквивалентны
varre = newRegExp("ab+c", "i");
s.match(re); // массив содержащий результаты сопоставления, или null
s.search(re); // индекс первого сопоставления с регулярным выражением
s.replace(re, st); // возвращает строку с проведенными заменами
s.split(re [, num]); // разбить строку (не больше num элементов)
Символы регулярных выражений
^ в начале строки
$ в конце строки
[xy] один из символов. [abcd] - то же, что [a-d]
[^xy] любой символ, кроме указанных
x|y находит x или y. Например, /green|red/
\s пробельный символ
\S не пробельный символ
\w словесный (латинский алфавит) символ. Эквивалентно [A-Za-z0-9_]
\W не словестный. Эквивалентно [^A-Za-z0-9_]
\d цифра [0-9]
\D не цифра [^0-9]
\b граница слов (латинских)
\B не граница слов (латинских)
\xhh шестнадцатиричный символ hh
\A начало текста (?)
\Z конец текста (?)
\< начало слова (?)
\> конец слова (?)
. любой символ (точка), кроме перевода строки
[\s\S] что угодно, включая перевод строки
(x) находит x и запоминает в массиве-результате поиска $1, ..., $9
(?:x) пассивная группа находит x, но не запоминает (просто объединение в один подпатерн)
x(?=y) находит x, только если за x следует y. Например, /Jack(?=Sprat)/
x(?!y) находит x, только если за x не следует y.
(...) группа (шаблон)
\4 4-я группа
* повторение 0 или более раз /bo*/ найдет 'booo'; если нужен символ *, то пишем \*
+ повторение 1 или более раз
{n} ровно n повторений: /a{2}/ не найдет 'a' в "candy," но найдет оба a в "caandy"
{n,} находит n и более повторений
{n,m} находит от n до m повторений
? может быть и не быть.
Если стоит после *, +, ?, или {}, то "нежадный" поиск (повторение минимальное количество раз,
до ближайшего следующего элемента паттерна), в противоположность "жадному" режиму по умолчанию,
при котором количество повторений максимально, даже если следующий элемент паттерна тоже подходит.
Примеры регулярных выражений:
s = s.replace(/\/\/.*/g, " "); // удаляем строчные комментарии
s = s.replace(/\/\*[\s\S]*?\*\//g, " "); // удаляем блочные комментарии
s = s.replace(/\s+/g, " "); // удаляем переносы строк и лишние пробелы
s = 'Яблоки круглые и яблоки.';
s.replace(/яблоки/gi, 'груши'); // => груши круглые и груши.
varre = /([А-ЯЁа-яё]+)\s+([А-ЯЁа-яё]+)/;
'Джон Смит'.replace(re, '$2 $1'); // => Смит Джон (меняет местами слова в строке)
s = 'АБВГДЕЁЖЗабвгдеёжз';
arr = str.match(/[А-Д]/gi); // глобальный g поиск, игнорирование регистра: i
При выводе информации внутрь div, имеющего некоторое id, используется функция getElementById
if( document.getElementById('check_id').checked ) { // выбран ли чекбокс
document.getElementById('div_id').innerHTML = 'Hello world!'; // для div
document.getElementById('text_id').value = 'Hello world!'; // для textarea
}
Обработка нажатия клавиш
Есть три функции, вызываемые при нажатии клавиши на поле редактирования:
keyup - после добавления символа в строку;
keydown - до добавления символа в строку;
keypress - сразу после keydown, если нажата символьная клавиша (нажатие приводит к символу).
Код нажатой клавиши находится в event.keyCode.
Внимание! в Firefox код ";" равен 59, а в остальных браузерах - 186.
Аналогично "=" - 107 и 187, "-" - 109 и 188.
Пример:
// Прочитать текстовый файл и вернуть содержимое. @param file имя файла
functionreadTextFile(file){
varrequest = newXMLHttpRequest();
request.open("GET", file, false);
request.send(null);
returnrequest.responseText;
}
В Google Chrome по умолчанию чтение с диска локальных файлов запрещно. Чтобы это обойти,
необходимо все Chrome-ы закрыть, а потом запустить с параметром --allow-file-access-from-files
(на иконке правая кнопка мыши, Properties и в поле Target добавляем этот параметр).