Что такое JavaScript?

Что такое JavaScript? Программирование

Каждый пользователь интернета, так или иначе пользуется прелестями JavaScript. Возможно, не все пользователи это понимают, но это факт. Современный веб и юзабилити построены в основном на JavaScript и прилегающих к нему библиотеках и фреймворках. Просто запуская браузер, вы уже сталкиваетесь с JavaScript.

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

Начинаем!

Внимание!

Друзья, дальше будет много кода. Я указываю комментарии после двойного слэша //. Также я проставляю нумерацию, чтобы показать вам в какой очередности будет выполняться код. Так вам будет удобнее читать и понимать, что выполняется первым, а что последним.

Что такое JavaScript?

Если коротко, то JavaScript добавляет интерактивность на веб-страницу. Переходы, различные анимации, всплывающие окна, заполняемые формы, слайдшоу — это все делает JavaScript.

JavaScript достаточно прост и интуитивен, он очень легок в обучении, поэтому входит в тройку самых популярных языков программирования. Однако, JavaScript не работает в одиночку, чаще всего он применим с HTML (разметка) и CSS (таблица стилей). При изучении языка важно понимать, что JavaScript очень часто взаимодействует с ними.

Где используется JavaScript?

Браузерная игра в Google Chrome написанная на JavaScript
Браузерная игра в Google Chrome написанная на JavaScript

Как уже говорилось выше, JavaScript используется на вебсайтах, но не только. Помимо вебсайтов JS часто применяется в таких областях как:

  • Браузерные игры
  • Мобильные приложения (JS не привязан к операционной системе)
  • Презентации

Хоть и язык JavaScript считается клиентским языком (выполняется не на сервере, а на стороне клиента, т.е на вашем компьютере), но его можно использовать и в серверных приложениях, и используют.

В чем разница между Java и JavaScript?

Хочется сразу сказать, что общего между ними только «Java» в названии. Хоть Java и используется для разработки веб-страниц. Так в чем же разница? Java — это объектно-ориентированный язык программирования, а JS — объектно скриптовый язык.

  • Синтаксис JS не так строг как Java, что делает его легким в обучении и освоении для большинства людей (гуглим явное и неявное приведение типов).
  • Компиляция. JS является интерпретируемым языком программирования, который интерпретируются строка за строкой во время выполнения. В том время как Java является скомпилированным языком. (Скомпилированные языки, как правило, быстрее)
  • Среда разработки. Java используется практически в любой среде, в то время как JS используется преимущественно в браузерах.
  • Использование ресурсов: Java тяжелее и более прожорлива, чем JS. Поэтому при создании веб-страниц, чаще всего, выбор падает на JS.

Безопасность JS

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

Ванильный JS

Ванильным JavaScript кодом зовут код, который написан исключительно на самом JS, без помощи каких-либо библиотек. В настоящее время такой код встречается крайне редко. Все пользуются различными библиотеками (React JS) и фреймворками (Vue, Angular). Библиотеки и фреймворки позволяют ускорять и упрощать процесс разработки.

Хуки в React JS
Хуки из библиотеки React JS

Однако, если вы только начинаете свой путь в освоении JS, все-таки лучше для начала ознакомиться и освоить ванильный JS. Это основа основ, элементарные знаниях о filter, find, map и пр. должны быть! Вы должны знать как ими пользоваться и в чем их отличия.

Основные компоненты JS

Как и все языки программирования, JS использует переменны для опредления местоположения хранения данных. Переменные бывают разные типов, глобальные — которые доступны в любом месте кода и локальные, которые доступны исключительно в месте, где они объявлены.

В чем разница между var, const и let?

До прихода ES6, все пользовались var — это глобальная и локальная переменная, которая имеет область видимости глобально и локально (в рамках функции). Это удобно, но вызывало некоторые проблемы. Если мы попытаемся объявить var локально, она все-равно будет видна на глобальном уровне (за исключением функций). Происходит поднятие, но об этом чуть ниже.

Рассмотрим простой код:

var sayHi = 'Hi' // 1. глобально объявлена

if (sayHi.length) {
    var sayHello = 'hello' // 2. Объявлена локально, в зоне видимости условия
    console.log(sayHi) // 3. Hi
    console.log(sayHello) // 4. Hello
}
console.log(sayHi) // 5. Hi
console.log(sayHello) // 6. Hello - потому что произошло "поднятие".
 

Код отработает корректно. В случае с var (в отличии от const и let) — совсем не важно, где объявленна переменная (искл. функции), она будет доступна везде. Этот же код, только используем const вместо var:

const sayHi = 'Hi' // глобально объявлена

if (sayHi.length) {
    const sayHello = 'hello' // объявлена локально
    console.log(sayHi) // Hi
    console.log(sayHello) // Hello
}
console.log(sayHi) // Hi
console.log(sayHello) // Uncaught ReferenceError: sayHello is not defined

Я думаю, что вам понятно стало, почему так произошло. Потому что переменная sayHello было объявленна локально и недоступна извне (У let и const — блочная область видимости, т.е переменная видна только на том уровне, на котором была объявлена). И еще…

Константу (const) нельзя создавать пустой, в отличии от var и let. При создании ей обязательно должно быть присвоено значение (необходимо инициализировать).

var a; // Так можно
let b; // И так можно
const c; // А так нельзя, ошибка: Uncaught SyntaxError: Missing initializer in const declaration

Окей, разобрались. Давайте посмотрим еще на такой код:

var sayHi = 'hi'

if (sayHi.length) {
    var sayHi = 'hello!'
}

console.log(sayHi)

Как вы думаете, что здесь выведет консоль? Выведет она: hello! Это тоже одна из проблем использования var. Объявленную переменную можно объявить снова. Когда у вас сотни, а то и тысячи строк кода, вы можете забыть, какое название для переменной вы уже использовали. Тем самым вы с легкостью можете сломать свой код, вы должны извращаться в названиях и не повторяться (const и let нас избавят от этого). Вот этот же код с использованием const:

const sayHi = 'hi'

if (sayHi.length) {
    const sayHi = 'hello!'
}

console.log(sayHi) // Выведет: hi

Ну, во-первых, константу переопределять нельзя. А во-вторых, теперь это две разные константы и хранятся они в разных участках оперативной памяти. Соответственно одна другой не мешает. Если у вас 50 циклов, в каждом из них вы можете повторять названия переменных, потому что область видимости ограничена.

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

for (let i = 0; i < 5; i++) {
    console.log(i);
    for (let i = 0; i < 3; i++) {
        console.log(i);
    }
}

// Такой код отработает корректно

Отработает он корректно, потому что объявлены две разные переменные i. Если вы замените let на var — вы сломаете браузер (код просто циклично замкнет и будет выполняться до тех пор, пока не зависнет браузер)

В циклах используется let, потому что значение константы (const) менять нельзя, на то она и константа.
const a = 1; a = 2 // Не отработает, выскочит ошибка.
let b = 1; b = 2 // Отработает корректно
var c = 1; c = 1 // Отработает корректно

P.S. Var — это устаревший вариант. Старайтесь использовать исключительно let и const. Данная часть была написана для общей образовательной базы, вы просто должны знать, что такое есть и в чем разница.

Поднятие переменных

Окей, продолжаем. Теперь, после того, как мы разобрались с переменными и различием между ними, перейдем к теме поднятия переменных. JavaScript позволяет использовать переменные до их объявления. Рассмотрим такой код:

console.log(name) // Denis
var name = 'Denis'

// Код отработает корректно

Такой код будет интерпретирован JS как:

var name = 'Denis'
console.log(name) // Denis

Однако, такое поведение доступно только с переменной name. (Потому что это свойство объекта window). Вообще, при поднятии глобальной переменной var присваивается undefined. Т.е допустим этот же код но с другим названием переменной:

console.log(age)
var age = 24;
console.log(age)

Будет интерпретирован JS как:

var age; // Происходит поднятие и присваивание undefined
console.log(age) // undefined
age = 24; // присваиваем значение
console.log(age) // 24

Это и называется поднятием. Глобальную переменную var, JS поднимает на самый верхний уровень. Но, пожалуйста, не делайте так! Это считается очень плохой практикой. (Да и в целом, как я уже говорил, старайтесь избегать переменной var).

Объекты JS

JavaScript основан на концепции объектов. Объекты — это контейнеры, которые могут содержать в себе свойства и методы. Давайте рассмотрим такой простой пример. Допустим, мы хотим создать объект «машина», у которой есть цвет и год выпуска.

// Вариант 1

let car = {
    color: 'red',
    year: 2021
}

console.log(car) // {color: 'red', year: 2021}

// Мы создали объект машина, у которой красный цвет и год 2021
// При создании объекта, не обязательно указывать свойства, можно сделать это позже

// Вариант 2

let car = {} // или let car = new Object();

car.color = "red"
car.year = 2021

console.log(car) {color: 'red', year: 2021}

С помощью функций можно создавать новые объекты не дублируя код:

function Car (color, year) {
    return {
        color,
        year
    }
}

let audi = Car('green', 2022)
let volvo = Car('red', 2021)

console.log(audi) // {color: 'green', year: 2022}
console.log(volvo) // {color: 'red', year: 2021}

К существующем объектам можно добавлять свойства и удалять, а также изменять:

function Car (color, year) {
    return {
        color,
        year
    }
}

let audi = Car('green', 2022)
console.log(audi) // // {color: 'green', year: 2022}

audi.color = 'blue' // изменим цвет машины
delete audi.year // удалим год из нашей машины
audi.everything = 'Можно добавлять что угодно'

console.log(audi) // {color: 'blue', everything: 'Можно добавлять что угодно'}

В объекты можно добавлять функции:

function Car (color, year) {
    this.color = color
    this.year = year
    this.saySmth = function() {
        console.log(this.color) // red
    }
}

let audi = new Car('red', 2014)

console.log(audi) // {color: 'red', year: 2014, saySmth: ƒ}
audi.saySmth()

Еще более подробно и развернуто об объектах (методах и свойствах) вы можете почитать здесь.

Классовый подход

Если коротко, class — это шаблон для создания объекта, который может содержать в себе свойства и методы. Функции работают с собственными свойствами и вызывать их можно извне. Классы позволяют более императивно подходить к созданию объекта.

Что такое императивный и декларативный подход?

Минутка познавательной информации…

Императивный подход — достигая цель, вы описываете весь процесс детально.
Декларативный подход — вы просто достигаете цели.

Например: Мама хочет послать Диму за хлебом, она должна выбрать каким способом это сделать:

Императивно: Дима, выйди из квартиры, спустись по лестнице, открой дверь подъезда, поверни направо, пройди 252 шага, поверни налево, зайди в магазин, возьми хлеб, подойди на кассу, заплати за него.

Декларативно: Дима, иди в магазин и купи хлеб.

Вернемся к нашим классам.

class Car { // Создаем класс Car
    constructor(options) { // Передаем в него параметры
        this.brand = options.brand; // определяем параметры
        this.color = options.color; // определяем параметры
        this.year = options.year; // определяем параметры
    }
    sayBrand() {
        return this.brand; // вернет this.brand тому, кто попросит
    }
}

let audi = new Car({brand: 'audi', color: 'red', year: '2021'}) // передаем объект с параметрами


console.log(audi); // Car {brand: 'audi', color: 'red', year: '2021'}
console.log(audi.brand) // audi
console.log(audi.sayBrand()); // audi (мы попросили, нам вернули)

На выходе получаем самый обычный, полноценный объект, с которым можно работать также как и с другими объектами — добавлять, изменять, удалять свойства. Окей, но что если нам теперь необходимо создать не машину, а самолет? Писать все заново? Нет. У классов есть наследование (extends), про него можно почитать на хабре и на mozilla MDN.

class Airplane extends Car { // Класс Airplane наследует класс Car
    constructor(options) {

    }
}

let air = new Airplane({brand: 'Airbus'})

console.log(air.brand) // Ошибка

// Код не отработает, что не так?

Код не отработает, потому что мы забыли очень важную деталь. Для того чтобы обращаться к родительскому классу и его конструктору, существует специальная функция: super() — позволяет запустить конструктор родителя из дочернего компонента. Давайте напишем правильно.

class Airplane extends Car {
    constructor(options) { // 2. Наш конструктор принимает options
        super(options) // 3. Вызываем родителя (class Car) и передаем ему эти параметры

    }
}

let air = new Airplane({brand: 'Airbus'}) // 1. Вызываем дочерний класс Airplane и передаем туда brand.

console.log(air.brand) // Airbus

Вы заметили, что мы в дочернем компоненте больше не пишем this.brand = brand? Этого делать не нужно, мы уже унаследовали все из родительского класса, где все поля подставились сами. Однако, если мы что-то хотим добавить в дочерний класс, чего нет в родительском, это необходимо прописывать. Например, мы хотим создать поле from:

class Airplane extends Car {
    constructor(options) {
        super(options)
        this.from = options.from // Добавили новое поле
    }
}

let air = new Airplane({brand: 'Airbus', color: 'white', year: '2022', from: 'Germany'}) // все остальные параметры, кроме from - у нас уже есть

console.log(air.from) // Germany
console.log(air) // {brand: 'Airbus', color: 'white', year: '2022', from: 'Germany'}

Прошу заметить, что from доступен только в классе Airplane, в классе Car его нет. Если мы попытаемся в класс Car передать объект содержащий поле from — ничего не произойдет, он просто будет отброшен.

let audi = new Car({brand: 'Audi', color: 'black', year: '2022', from: 'Germany'})
console.log(audi) // {brand: 'Audi', color: 'black', year: '2022'}

Где это бывает полезно? Когда вы хотите создать пользователей от админа до простого юзера, с каждым новым классом вы увеличиваете права доступа. Также вы можете использовать методы родительского класса. Вспомним, что у нас в классе Car есть метод sayBrand(), который выводит нам в консоль бренд марки автомобиля, теперь он нам будет выводить марку самолета.

class Airplane extends Car {
    constructor(options) {
        super(options)
        this.from = options.from
    }
}

let air = new Airplane({brand: 'Airbus', color: 'white', year: '2022', from: 'Germany'})

console.log(air.sayBrand()) // Germany

Вся эта магия происходит благодаря super(). Давайте взглянем полностью на весь код, что мы написали.


class Car {
    constructor(options) {
        this.brand = options.brand;
        this.color = options.color;
        this.year = options.year;
    }
    sayBrand() {
        return this.brand;
    }
}

class Airplane extends Car {
    constructor(options) {
        super(options)
        this.from = options.from
    }
}

let air = new Airplane({brand: 'Airbus', color: 'white', year: '2022', from: 'Germany'})
let audi = new Car({brand: 'Audi', color: 'black', year: '2022', from: 'Germany'})



console.log(audi) // {brand: 'Audi', color: 'black', year: '2022'}
console.log(air) // {brand: 'Airbus', color: 'white', year: '2022', from: 'Germany'}


console.log(audi.sayBrand()) // Audi
console.log(air.sayBrand()) // Airbus

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

Массивы

Объекты — это конечно интересно, но сейчас поговорим про массивы. Объекты хранят в себе информацию ключ + значение, однако объекты хаотичны и тяжело (точнее, не предоставляется возможным) из них сделать упорядоченную коллекцию данных. Что это значит? Сейчас объясню.

У массивов есть индекс элемента, а у объекта нет. Т.е давайте рассмотрим такой код:

let carsArray = ['audi', 'volvo', 'mercedes']
console.log(carsArray)

let carsObjects = {
    audi: 'audi',
    volvo: 'volvo',
    mercedes: 'mercedes'
}
console.log(carsObjects)

Мы создали массив элементов и объект. Посмотрим, что нам выдала консоль:

console.log js
console.log js

В массиве есть индекс 0, 1, 2… (в программировании счет всегда идет с 0), а в объекте нет. Казалось бы, почему нам самим не проставить? Ну потому что чаще всего мы не создаем объекты, а получаем их с сервера. А еще чаще мы получаем массив объектов с индексом.

К любому элементу массива мы можем обратиться по его индексу:

let carsArray = ['audi', 'volvo', 'mercedes']
console.log(carsArray[0]) // audi

Мы можем изменить его:

let carsArray = ['audi', 'volvo', 'mercedes'];
console.log(carsArray[0]); // audi

carsArray[0] = 'honda';
console.log(carsArray[0]); // honda

А можем и удалить:

let carsArray = ['audi', 'volvo', 'mercedes'];

carsArray.forEach((item) => { // обходим каждый элемент массива
    if (item === 'volvo') { // проверяем совпадает ли условие (нам нужен элемент volvo)
        let index = carsArray.indexOf(item); // находим индекс элемента
        carsArray.splice(index, 1); // удаляем элемент из массива
    }
});
console.log(carsArray); // ['audi', 'mercedes']

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

let cars = carsArray.filter( (item) => item !== 'volvo')
console.log(cars) // ['audi', 'mercedes']

Маленький совет…

Если вы только учитесь или собираетесь (а раз вы это читаете, значит вы один из двух), старайтесь не использовать стрелочные функции. Прописывайте код полностью, делите на строчки. Такой код проще дебажить и отслеживать, что, куда, откуда и зачем приходит. Как только вы поймете, что вы и без debugger’a понимаете, что и куда должно идти, тогда можете приступать к оптимизации своего кода.

Массивы — очень классная вещь, есть очень много различных методов работы с массивами, удаление, добавление, редактирование, поиск, перебор и много-много всего интересного, про сами массивы вы можете почитать здесь, а про методы работы с массивом здесь.

Функции JavaScript

Переходим вероятней всего в заключительную часть. (Есть еще куча всего, о чем я вам не поведал, например, промисы и асинхронность, но на начальном уровне это не то, что вам надо знать, может слегка напугать 🙂 ). Окей, функции, поехали:

Для чего нужны функции? Зачастую нам надо повторять несколько раз один и тот же код. Допустим, мы хотим вывести приветствие три раза, что нам необходимо сделать? Да, мы можем написать так:

alert('Привет!')
alert('Привет!')
alert('Привет!')

Сработает это? Да! Правильно ли это? Нет. Дублировать код считается плохой практикой, поэтому нам приходят на помощь функции.

function sayHello () { // создаем функцию с именем sayHello
    for (let i = 0; i < 3; i++) { // создаем цикл, который проверяет, сколько раз функция сработала
        alert('Привет!') // выводим наше приветствие 3 раза
    }
}

sayHello() // вызов функции

Круто! Не правда ли? Окей, давайте немного усложним наш код. Теперь мы будем приветствовать пользователя.


let name = 'Denis' // 1. Создаем переменную

function sayHello () { // 3. функции имеют доступ к внешним переменным
    for (let i = 0; i < 3; i++) { // 4. создаем цикл, который проверяет, сколько раз функция сработала
        alert('Привет! ' + name ) // 5. выводим наше приветствие: Привет! Denis
    }
}

sayHello() // 2. Вызываем функцию

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

function showUserName(text, callback) { // 2. Принемаем первым арг - текст Hello, вторым - наш callback userName
    let name = 'Denis' // 3. создаем переменную name локально
    callback(text, name); // 4. после отработки всей функции вызываем наш коллбэк
}
function userName(text, name){ // 5. колбэк принимает параметры text и переменную name.
    console.log(text, name) // 6. Выводим в консоль: Hello, Denis
}
showUserName('Hello, ', userName); // 1. Вызываем функцию и передаем туда текст и callback функцию

Функция, передаваемая в другую функцию — зовется коллбэком (callback — обратный вызов). Зачем нам это надо? Чаще всего это используется в асинхронных функциях, где нам необходимо дождаться ответа запроса (например полной загрузки скрипта), а затем выполнить его.

Задачи принято делегировать на множество других разных задач. Это помогает сохранить читабельность вашего кода. Не надо все пихать в одну функцию, разбивайте свой код на компоненты (множество функций).

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

let userAnswer = 'qweqweqweeqwkeqwekj' // 1. представим, что мы попросили ввести пользователя число, но он ввел это.
let regExp = /^[0-9]+$/g // 2. Это регулярное выражение, которое проверяет на наличие определенных символов. (В данном случае проверяет на наличие чисел)


function userAnswerFunc(userAnswer) { // 4. Получаем ответ пользователя
    let flag = checkAnswerIsNumber(userAnswer) // 5. Передаем в другую функцию  наш ответ для проверки
    //  8. получили результат и записали его в переменную flag
    if (flag) { // 9. теперь проверяем flag true или нет
        console.log(userAnswer) // если да, то пишет в консоль число
    } else {
        console.log('Not a Number') // если нет, то пишем, что это не число
    }
}

function checkAnswerIsNumber(userAnswer) { // 6. Принимаем ответ
    return regExp.test(userAnswer)  // 7. Возвращаем результат проверки true или false
}


userAnswerFunc(userAnswer) // 3. Запускаем нашу функцию и передаем туда ответ пользователя

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

Заключение

Мальчики и девочки, я еще много о чем вам не поведал (циклы, ветвления, промисы, асинхронность, запросы на сервер и много всего-всего). Нельзя вот так просто взять и рассказать обо всем и сразу. Цель статьи — ответить на начальные вопросы, которые могут возникать. У меня есть несколько друзей, которые начали изучать JavaScript, они постоянно задают одни и те же вопросы, теперь смогу им просто скидывать ссылку 🙂

Если у вас есть какие-либо вопросы, задачки и пр. Я с радостью отвечу и дополню свою статью. Это не окончательный ее вариант, по мере поступления популярных вопросов и просьб разъяснить что-либо, я буду дополнять ее.

Я рассказал исключительно об основных вещах, отличиях и дал (надеюсь) примерное понимание как и что работает. Учебу вы должны продолжать самостоятельно, это не тяжело, как может показаться на первый взгляд. Дальше список полезных сайтов.

Полезные сайты для изучения JavaScript

learn.javascript.ru — разумеется, самый первый сайт, который вы должны посетить. Это учебник по JS, в котором куча отличного материала. Там все поделено на главы, можете начинать с первой и идти прямо по главам. Вы к этому сайту еще не раз вернетесь!

developer.mozilla.org — для тех кто знает, что именно он ищет. Очень хорошая документация. Есть и на русском и на английском языке (Лучше читайте на английском, документация обновляется быстрее).

doka.guide — наткнулся на сайт в твиттере, совершенно случайно. Но люди очень заморочились и сделали классную доку. Рекомендую!

JavaScript ES6: 7 полезных фишек — моя новая статья про фишки из ES6.

Про авторское право итд итп

Про авторское право итд итп

Напоминаю! Что это только первоначальный вид статьи, со временем она будет дополняться! Я очень долго писал и готовил этот материал, я разрешаю копирование и распространение с указанием ФИО автора и ссылкой на одну из соц. сетей автора, можно и на эту статью.

Автор: Булкин Денис
Twitter: http://twitter.com/denidenx
LinkedIn: https://www.linkedin.com/in/denidenx/

Еще чуток… Несмотря на то, что изначально данный сайт и проект планировался как коммерческий, эта статья и ей подобные лонгриды написаны не с коммерческой целью, 0 рублей с этого заработано. Просто возникло желание написать, с надеждой, что кому-то поможет. Спасибо! Берегите себя!

Дорогу осилит идущий.

Оцените статью
GeekБлог
Добавить комментарий