Записки по JavaScript
Содержание:
Комментарии
Строчный можно поместить в блочный, но блочные не могут быть вложенные.
// Строчный комментарий /* Блочный комментарий */
Переменные
- Переменные регистрозависимы, от "A" до "z".
- Строгой типизации нет, переменные универсальные, им можно присваивать различные типы.JavaScript является динамически типизированным.
- Имя должно начинаться с
- буквы
- нижнего подчёркивания (_)
- или знака доллара ($)
- последующие символы могут также быть цифрами (0-9).
- Имя не может начинаться на цифру
- Принято использовать "верблюжью нотацию" — пишут в нижнем регистре, символ верхнего регистра используется только на стыке слов, например userName, myFirstScript, myVar. Но первый символ должен быть в нижнем регистре.
- Исключение - "pascal notation", используется в функциях конструкторов, начинается с символа верхнего регистра MyVar
- Названия констант пишут в верхнем регистре.
- Константы менять нельзя, но значение объектов в константах менять можно.
- Переменные объявлять не обязательно, они объявляются при первом присвоении, но лучше так не делать.
- В коде непонятно, это присвоение идёт новой переменной или уже существующей
- Область видимости. Если var, то в блоках кода {var myVar01;let myVar02;} переменная myVar01 глобальная, если let, то myVar02 локальная.
- Лучше включить strict mode "use strict"; в начале.
const PI; var myVar01; //Устаревшее объявление. let myVar01; //Современное объявление(рекомендуется использовать). let myVar1 = 33; // Лучше использовать объявление с присвоением.
Если переменная объявлена, но значение не присвоено, то по умолчанию оно будет равно "undefined".
Операции и операторы
Операция | Описание |
---|---|
+ | сложение |
- | вычитание |
* | умножение |
/ | деление |
% | остаток от деления, 5%2 → 1 |
Выполняется справа → налево.
age = 30 + 1.5*2 p = age + 2
Вычисляется умножение, потом сложение и присваивается переменной age.
Переменная принимает значение "NaN" - "Not a number", когда вычисляется ошибочное значение, но это числовой тип.
age = 'abc' p = (age +2) *2; console.log(age);
Действие | Тип |
---|---|
1/0 | Infinity |
-1/0 | -Infinity |
0/0 | NaN |
Типы данных
Тип | Описание |
---|---|
undefined | Тип данных, которые не определены |
null | Нулевой тип данных, можно обнулять значение переменной |
int | Числовые:целые, вещественные, бесконечность. Можно ипользовать разделили в больших числах. 123_000_000 == 123 миллиона |
string | |
boolean | |
Объекты | |
Массив | |
Функция | |
Регулярные выражения |
Посмотреть тип значения переменной
typeof age
Округление
Math.round() Math.floor() Math.ceil() "100" + 1 = "1001" // + интерпретируется, как конкатенация по операнду слева. x = parseInt("100")+1 //100, преобразование в целое из строки. "100asdfdf" будет корректно обработано, т.к. обработка идёт с начала строки. x = parseFloat("200") // в вещественное
Сокращённый оператор присваивания.
x = 10; console.log(x); x = x + 6; //Работает справа налево, в начале вычисляется x+6 и присваивается x x +=6; //Тоже самое, что и выше. Сокращённый оператор присваивания. "Синтаксический сахар", когда одно действие можно записать по разному. x=1; //++ - плохая конструкция, которую трудно читать. UB - undefined behavior //Разница проявится при присвоении ++x; //префиксный инкремент x++; //постфиксный инкремент //Оператор присваивания let a; let b = a = 5; //Разбирается справа налево, a=5, b=a 5 let b = a++ = 5; //Разбирается справа налево, a=5, b=a 5, потому что ++ будет после присваивания let b = ++a = 5; //Разбирается справа налево, a=5, b=a 6, потому что присвоение будет для a+1 let a = 10; //let b = (a = a + 1 ) + (a = a + 1) //b = (11) + (12) //let b = ++a + ++a //b = 11 + 12 //let b = a++ + +aa //b= 10 + 12 let b = ++a + a++ //b = 11 + 11
Получение данных от пользователей
let userName; userName = prompt("Введите имя:","Иван"); age = parseInt(prompt("Введите возраст:","54")); let result = "Привет, " + userName + "!"
Логические /булевы операции
let a = true; let b = false; //ЛОГИЧЕСКОЕ И let c = a && b; // False //ЛОГИЧЕСКОЕ ИЛИ c = a || b; // True //ЛОГИЧЕСКОЕ НЕ c = !a; //False c = !(a && b) // !a || !b // True (n /2 ) == (n - 5) // Оператор сравнения
Операторы сравнения
При сравнении JavaScript будет делать приведение типов, поэтому существует опратор ===
Оператор | Описание | |
---|---|---|
== | сравнение на равенство | true, если равны, false, если не равны |
!= | сравнение на неравенство | true, если не равны, false, если равны |
=== | сравнение на равенство с учётом типа. | всегда false, если типы разные, true если типы и значения равны |
!== | сравнение на равенство с учётом типа. | всегда true, если типы разные, true если типы и значения равны |
> | больше | |
< | меньше | |
>= | больше или равно | |
⇐ | меньше или равно |
let x = 50; (x > 0) && < (x <=100) // true
Битовые операции
Работают с целыми числами
let a = 5; //0101 let b = 7; //0111
БИТОВОЕ И
- 1 если оба разряда 1
- 0 если оба разряда 0
- 0 если один из разрядов 0
let c = a & b; //0101 5 ==== БИТОВОЕ ИЛИ ==== * 1 если один из разрядов 1 * 0 если оба разряда 0 <code JavaScript> с = a | b; //0111 7
БИТОВОЕ ОТРИЦАНИЕ
- Меняет все биты на противоположные
- Знак целого числа хранится, как бит, поэтому знак тоже поменяется на противоположный.
с = ~a; -6
БИТОВОЕ ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR)
- 1 в несовпадающих битах
- 0 в совпадающих битах
c = a ^ b; 2 //0010
БИТОВЫЙ СДВИГ ВПРАВО на N Разрядов >>
Сдвигаем все биты вправо и указываем на сколько разрядов
c = a >> 2; // 0101 >> 2 == 0001 с = a << 2; // 0101 << 2 == 010100
Тип данных СТРОКОВОГО ЛИТЕРАЛА
- Нет отдельного типа - символ
- Между двойными и одинарными кавычками разницы нет
- Внутри строк работают ESC последовательности "\n", "\t", "\u002F"(символ по коду)
- + это символ конкатенации, "Привет"+ "Сергей"
- Можно использовать шаблоны, используются backtick - обратные апострофы, let result = `Привет, ${userName}!`
let result = 'Привет "+ userName + "!" let result = `Привет, ${userName}!`
Условный оператор if (ветвление)
Правило ЛЖИ(что считается ложью)
- false
- undefined
- null
- 0
- Nan(Not a Number) 0/0
- ''(две кавычки)
Всё остальное → ИСТИНА
- 1/0 Infinity
Короткий вариант
let n = 10; if (n > 0) console.log("n больше нуля"); if (n > 0) { console.log("n больше нуля"); console.log("n > 0 "); }
let n = -10; if (n > 0) { console.log("n больше нуля"); } else if (n > -100) console.log("n больше -100"); else console.log("n меньше -100");
let x = 1 / 0 if (x) console.log("True"); else console.log("False");
Тернарный оператор
let s = (n==0) ? "Ноль" : "Не ноль";
Операторы логического присваивания ECMAScript 2021
(||=) Оператор логического OR присвоения проверяет правый операнд и назначает его левому, если слева операнд равен false. (&&=) Оператор логического AND присвоения проверяет правый операнд и назначает его левому, если слева операнд равен true.
const a = { duration: 50, title: '' }; a.duration ||= 10; console.log(a.duration); 50 //Значение a.duration существует, значит True и значение 10 не присваивается. a.title ||= 'title is empty.'; console.log(a.title); "title is empty." //Значение a.title пустое, значит false и присваевается значение 'title is empty.' // AND let (z) =20; if (z) z=5; // или z &&=5 // присваевает, если z истина let secondUserName; secondUserName ??= "Unknown"; // присваивает значение, если secondUserName Undefined или null console.log(secondUserName);
Оператор ветвления switch
- switch прыгает на значение и выполняются все case до конца.
- break выполняет выполнение switch
- Если switch внутри функции и является последним оператором, то можно использовать return вместо break;
let n = 2; switch (n) { case -1: // тогда и -1 и 1 сработает case 1: console.log("1"); break; case 2: console.log("1"); break; default: // если значение не было найдено console.log("значение не найдено.") break; //можно не писать. }
Циклы
- Инициализация "счётчика"
- Проверка условия
- Выполнение инструкций
- Изменение "счётчика"
Цикл(for)
- break - останавливает выполнение цикла
- continue останавливает выполнение текущей итерации и переходит к следующей итерации
for (let i =1; i <= 10; i++){ if(i == 3) continue; if(i == 8) break; document.write(i); document.write('<br>'); }
Вывод таблицы
document.write("<table border=1>"); for(let i=1; i<=10;i++){ document.write("<tr>"); for(let y=1; y<=10;y++){ document.write(`<td>${i}.${y}</td>`); } document.write("</tr>"); } document.write("</table>");
Цикл с условиями while / do while
Цикл с предусловием while
- Условие проверяется перед каждой итерацией.
- Если условие не равно True, то итерация цикла выполняться не будет
let a =2; while (a < 1000){ document.write(a); document.write('<br>'); a*=2; // a = a* 2 }
Цикл с постусловием do while
- Гарантировано выполняется одна итерация
let a = 2000; do { document.write(a); document.write('<br>'); a*=2; // a = a* 2 } while (a < 1000)
Цикл (foreach)
console.log(navigator.userAgent); document.write(`<h1 style="color: rgb(226, 116, 43);">foreach</h1><p>`); document.write("<p>"+navigator.userAgent+"</p>"); document.write("<p>"+navigator.language+"</p>"); for(let property in navigator){ document.write("<p>"+property+":"+navigator[property]+"</p>"); } document.write("</p>")
Функции (function)
- Функцию можно вызывать до её объявления, т.к. интерпретатор в начале смотрит все определения и потом запускает. Поддерживается в функциях задекларированных классическим способом.
- Анонимные функции можно вызывать после определения
- return оператор завершения функции.
- returnов может быть несколько, но желательно, чтобы был один.
- Переменные в функции являются локальными, если они объявлены внутри функции с помощью let или var;
- window.переменная - Обращение к глобальной переменной, но переменная должна быть определена через var.
- Если не использовать var или let внутри функции и переменной присвоить значение в теле функции, то она станет глобальной. Поэтому лучше использоваться strict mode
document.write(`<h1 style="color: rgb(226, 116, 43);">Function</h1><p>`); function sayHello(userName,age){ // age ??= 18 // Default value, если значение слева пустое, то присваиваем 18 if(age) document.write(`<p style="font-size:28px;">Hello, ${userName}. Возраст: ${age}</p>`) else document.write(`<p style="font-size:28px;">Hello, ${userName}</p>`) } sayHello('Sergey',34); sayHello('Pavel',92); sayHello('Анна'); function average(a,b){ let avg = (a+b)/2; return avg; } let x= average(12,34) document.write(`<p style="font-size:28px;">x= ${x}</p>`)
Функция, как выражение.
- Функцию можно положить в переменную и вызывать, как переменную.
- Это позволяет передавать функцию, как параметр.
function bar(){ let z=10; return z; } let barVar = bar // bar() не вызывается document.write(barVar()); // вызов функции, которая лежит в переменной. document.write( typeof barVar); // посмотреть тип, будет function
Анонимные функции
- Функция может быть анонимной, когда опускается название функции.
- Анонимные функции можно вызывать после определения.
function test(){ document.write("<br> Test"); } let testVar=test(); test(); testVar(); //или //анонимная функция let testVar1 = function (){ document.write("<br> Test1"); } testVar1();
Объекты
- Сложная программная сущность, которая группирует внутри себя несколько переменных, под некоторыми уникальными в рамках этого объекта именами.
- Объкты могут содержать свойства(поля) и методы(функции), оперирующая данными этого объекта.
- Функции конструкторы с большой буквы, например Object
- . - Обращение к свойствам и методам объекта
- this - указатель на текущий объект
1. Создание пустого объекта, потом добавление свойств и методов.
let book1 = new Object(); console.log(typeof book1); book1.title = 'Улитка на склоне'; book1.price = 300; function renderBook(){ document.write(`<p>Название:${this.title} Цена:${this.price}</p>`) } book1.render = renderBook; //добавляем функцию в объект book1.render();
2. Массивы
- Элементы массива могут иметь разные типы, но это плохая практика.
- Массив имеет динамический размер, в остальных языках он фиксированный
- Массив в JavaScript это коллекция
- Нумерация начинается с 0
- Существует метод .at(-1) и тогда можно обращаться к элементам с отриц. значением и концом. появилось в 22 году
let colors = ['red','green','blue']; let colors1 = new Array('red','green','blue'); //устаревший способ console.log(colors); console.log(colors.length); //Длина массива colors[0] = 'pink'; // Замена первого элемента массива console.log(colors[0]); console.log(colors[colors.length-1]); //Последний элемент массива for(let i = 0; i < colors.length; i++){ document.write(`<br> ${colors[i]}`); } let s = colors.join("-") //Объединение в строку с разделителем console.log(s); let stateStr="Россия.США.Китай.Германия.Япония" let states = stateStr.split(".") console.log(states) console.log(states.sort()) //Сортировка states = states.join("#") console.log(states) // Удаление последнего элемента console.log( colors.join()) let last = colors.pop() //Удаление последнего элемента и помещение его в переменную last console.log( colors.join()) console.log( last) // Добавить в конец массива элемента console.log( colors.join()) console.log( colors.push('yellow')) console.log( colors.join()) //Удалить и добавить первый элемент console.log( colors.unshift('grey')); //Добавление в начало console.log( colors.join()) console.log( colors.shift(0)); // Удаление первого элемента со сдвигом всех элементов console.log( colors.join()) colors.reverse() //Реверсно переставить элементы console.log( colors.join()) //Сортировка чисел, по умолчанию сортирует, как строки let nums = [123, 2, 34, 55, 99, 45, 24, 71, 64]; console.log(nums.join()); nums.sort(); console.log(nums); //Надо передать функцию сравнения для сортировки function compareNumbers(x,y){ if (x > y) return 1; if (x < y) return -1; if (x == y) return 0; } nums.sort(compareNumbers); // Теперь сортирует, как числа. console.log(nums); //Можно переделать функцию function compareNumbers(x,y){ // if (x > y) return 1; // if (x < y) return -1; // if (x == y) return 0; return x - y; } nums.sort(compareNumbers); console.log(nums); // Можно описать анонимной функцией let cmp = function (x,y){ return x - y; } nums.sort(cmp); console.log(nums); // реверсная сортировка, сортировка по убыванию let cmpr = function (x,y){ return y - x; } nums.sort(cmpr); console.log(nums); //Анонимная функция nums.sort(function (x,y){return x-y;}); console.log(nums); //Cтрелочная функция =>, Лямбда выражение в других языков nums.sort((x,y)=>{return x-y;}); nums.sort((x,y)=>x-y); //убираем return и фигурные скобки, если функция имеет только один return console.log(nums); colors.findIndex( e=>e.length==3); //Ищет с начала и возвращает индекс colors.find( e=>e.length==3); //Ищет с начала и возвращает значение //ECMA23 colors.findIndexLast( e=>e.length==3); //Ищет с концца и возвращает индекс colors.findLast( e=>e.length==3); //Ищет с конца и возвращает значение //группировка let g = Object.groupBy(books, (element,index)=>element.price>100?'high':'low') console.log(g); //группировка let g1 = Maps.groupBy(books, (element,index)=>element.price>100?'high':'low') console.log(g1);
Объекты. Конструкторы.
//Функции конструкторы принято называть с большой буквы. function renderBook(){ document.write(`${this.title} - ${this.price}`); } function Book(title,price){ this.title = title; this.price = price; let _title = title; // Присвоение локальной переменной для защиты от изменения. Старый способ. По точке этого свойства не будет, доступно только методам объекта. //this.render = renderBook; this.render = function(){ document.write(`${this.title} - ${this.price}<br>`); }; this.GetTitle = function(){return _title;} //новый способ, создание метода, возвращающего приватное свойство } let book1 = new Book('Улитка на склоне', 300); let book2 = new Book('Лестница в небо', 200); book1.render(); //this === book1 book2.render(); //this === book2 book1.title = "Над пропостью во ржи" book1.render(); //this === book1
Прототипы [[prototype]]
- Элемент ненумерованного списка в каждом объекте JavaScript может быть поле prototype
- Мы не можем к нему обращаться, он недоступен.
render добавлено в prototype
function renderBook(){ document.write(`${this.title} - ${this.price}`); } function Book(title,price){ this.title = title; this.price = price; let _title = title; // Присвоение локальной переменной для защиты от изменения. Старый способ. По точке этого свойства не будет, доступно только методам объекта. // this.render = renderBook; // this.render = function(){ // document.write(`${this.title} - ${this.price}<br>`); // }; this.GetTitle = function(){return _title;} //новый способ, создание метода, возвращающего приватное свойство } let book1 = new Book('Улитка на склоне', 300); let book2 = new Book('Лестница в небо', 200); //book1.render(); //this === book1 //book2.render(); //this === book2 //book1.title = "Над пропостью во ржи" //book1.render(); //this === book1 Book.prototype.render = function(){ document.write(`${this.title} - ${this.price}<br>`); } book1.render(); //this === book1 в объекте render нет, а в прототипе есть. book2.render(); //this === book2
Классы
- Классы это надстройка над прототипами
- 20 лет в JavaScript не было понятия классов
- Класс - понятие типов данных объектов
- В JavaScript нет понятия разных типов данных для объктов, они формально все одного типа - object.
- Вся объектная модель основывалась на прототипах.
- Классы появились с 2015 года в JS.
- Классы в JS это надстройка, технически JS всё так же работает с прототипами.
class Book { #title; // # - Private field since ECMAScript 2022 price = 0; constructor(title, price){ this.#title = title; this.price = price; } render(){ document.write(`${this.#title} -${this.price} <br>`) } } let book1 = new Book('Улитка на склоне', 300); let book2 = new Book('Лестница в небо', 200); book1.render(); //this === book1 book2.render(); //this === book2
Строки
- Строки в JavaScript являются незименяемым объектом, т.е. все методы создают на основе строки новую строку, которую можно присвоить переменной.
- В 2021 году появился метод ReplaceAll - замена всех вхождений подстроки в строке.
let Result = "My Very Long String!" let a = Result.indexOf("Long1") console.log(Result); console.log(Result.length); //Длина строки console.log(Result.charAt(0)); //Символ по номеру console.log(Result.toUpperCase()); //Перевод в верхний регистр console.log(Result.indexOf("Long")); //Поиск подстроки, номер симовола или ложь(-1) если не найдено document.write(navigator.userAgent); let isChrome = navigator.userAgent.indexOf("Chrome") >=0; console.log(isChrome); //Подстрока console.log(Result); console.log(Result.substring(3,9)); //Very L с 3 по 9 console.log(Result.substring(3)); //Very.. с 3 по 9 //Замена console.log(Result); console.log(Result.replace("Long","Short"));
Обработка ошибок
try / catch
let n = - 101; console.log(n) console.log('Before error') if (n < 0 || n > 100){ throw new Error('n out of [0,100]') console.log('After error') } //let n = - 101; try{ if (n < 0 || n > 100){ console.log(n) console.log('Before error') throw new Error('n out of [0,100]') console.log('After error') } } catch(e){ console.log(e) }
Регулярные выражения
- RegExp - два способа описания регулярного выражения, через RegExp и через '/'
let phone = '011-45-78'; let reg = RegExp('\\d\\d\\d-\\d\\d-\\d\\d') let reg3 = /[1-9]\d\d\d-\d\d-\d\d/ig; let reg1 = RegExp('\\d{3}-\\d{2}-\\d{2}') let reg2 = RegExp('[1-9]\\d{2}-\\d{2}-\\d{2}') if(reg3.test(phone)){ console.log("Yes") }else{ console.log("No") }
JSON
//JSON JavaScript notation //{} - eq пустой объект let book1 = { title: "Улитка на склоне", price: 300, render: function(){ document.write(this.title + ' - '+ this.price + '<br>'); } }; book1.render(); let s = JSON.stringify(book1); // преобразование к строке, называется сериализацией console.log(s); console.log(typeof s); let book2 = JSON.parse(s); // из строки в объект, десереализация console.log(book2); let books = [ { title: "Улитка на склоне", price: 300, },{ title: "Лестница в небо", price: 100, },{ title: "Понедельник начинается в субботу", price: 200, } ] console.log(books); console.table(books); document.write('<table border=1 >') document.write(`<tr><td>Title</td><td>Price</td></tr>`) books.forEach(element => { document.write(`<tr><td>${element.title}</td><td>${element.price}</td></tr>`) }); document.write('</table>')
Работа с датами
let now = new Date('2025/02/05'); console.log(now); let myDayOfWeek = ('0' + now.getDay()).slice(-2); // День недели. slice - добивание 0 слева console.log(myDayOfWeek); let myDay = ('0' + now.getDate()).slice(-2); // День месяца console.log(myDay); let myMonth = ('0' + (now.getMonth()+1)).slice(-2); //Месяц. Начинается с 0 console.log(myMonth); var firstday = ("0"+(now.getDate() - now.getDay() + (now.getDay() == 0 ? -6 : 1))).slice(-2) console.log(firstday); var lastday = ("0"+(now.getDate()+ (7 - now.getDay()) )).slice(-2) console.log(lastday) let currentDate = `${firstday}.${myMonth}-${lastday}.${myMonth}` console.log(currentDate); // "17-6-2022"