Станьте экспертом в современном JavaScript и станьте лучше в React, Angular, Vue

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

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

В JavaScript внесено множество последних дополнений, таких как нулевой оператор объединения, необязательное связывание, обещания, async / await, ES6 деструктуризация и многие другие функции, которые очень полезны.

Давайте рассмотрим некоторые навыки современного JavaScript, которые вам следует знать.

Пусть и const

До появления ES6 в JavaScript использовалось ключевое слово var, поэтому JavaScript имел только функцию и глобальную область видимости. Не было области на уровне блока.

С добавлением let и const JavaScript добавил область видимости блока.

с помощью let:

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

// ES5 Code
var value = 10;
console.log(value); // 10
var value = "hello";
console.log(value); // hello
var value = 30;
console.log(value); // 30

Как видно выше, мы повторно объявили переменную value, используя ключевое слово var несколько раз.

До ES6 мы могли повторно объявить переменную, которая уже была объявлена ​​раньше, и которая не имела никакого значимого использования, вместо этого она вызывала путаницу.

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

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

// ES6 Code
let value = 10;
console.log(value); // 10
let value = "hello"; // Uncaught SyntaxError: Identifier 'value' has already been declared

Но следующий код действителен

// ES6 Code
let value = 10;
console.log(value); // 10
value = "hello";
console.log(value); // hello

Мы не получаем ошибку в приведенном выше коде, потому что мы переназначаем новое значение переменной value, но мы не объявляем повторно value снова.

Теперь взгляните на приведенный ниже код:

// ES5 Code
var isValid = true;
if(isValid) {
  var number = 10;
  console.log('inside:', number); // inside: 10
}
console.log('outside:', number); // outside: 10

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

// ES6 Code
let isValid = true;
if(isValid) {
  let number = 10;
  console.log('inside:', number); // inside: 10
}
console.log('outside:', number); // Uncaught ReferenceError: number is not defined

Как вы можете видеть в приведенном выше коде, переменная number при объявлении с использованием ключевого слова let доступна только внутри блока if, а за пределами блока она недоступна, поэтому мы получили справочную ошибку, когда пытались получить доступ к ней за пределами блока if.

Но если за пределами блока if была переменная number, она будет работать, как показано ниже:

// ES6 Code
let isValid = true;
let number = 20;
if(isValid) {
  let number = 10;
  console.log('inside:', number); // inside: 10
}
console.log('outside:', number); // outside: 20

Здесь у нас есть две number переменных в отдельной области. Таким образом, вне блока if значение number будет 20.

Взгляните на приведенный ниже код:

// ES5 Code
for(var i = 0; i < 10; i++){
 console.log(i);
}
console.log('outside:', i); // 10

При использовании ключевого слова var i был доступен даже вне цикла for.

// ES6 Code
for(let i = 0; i < 10; i++){
 console.log(i);
}
console.log('outside:', i); // Uncaught ReferenceError: i is not defined

Но при использовании ключевого слова let оно недоступно вне цикла.

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

Мы также можем создать блок с помощью пары фигурных скобок, например:

let i = 10;
{
 let i = 20;
 console.log('inside:', i); // inside: 20
 i = 30;
 console.log('i again:', i); // i again: 30
}
console.log('outside:', i); // outside: 10

Если вы помните, я сказал, что мы не можем повторно объявить переменную на основе let в том же блоке, но мы можем повторно объявить ее в другом блоке. Как видно из приведенного выше кода, мы повторно объявили i и присвоили новое значение 20 внутри блока, а после объявления это значение переменной будет доступно только в этом блоке.

Вне блока, когда мы напечатали эту переменную, мы получили 10 вместо ранее присвоенного значения 30, потому что вне блока внутренняя переменная i не существует.

Если переменная i не объявлена ​​снаружи, мы получим ошибку, как показано в приведенном ниже коде:

{
 let i = 20;
 console.log('inside:', i); // inside: 20
 i = 30;
 console.log('i again:', i); // i again: 30
}
console.log('outside:', i); // Uncaught ReferenceError: i is not defined

используя const:

Ключевое слово const работает точно так же, как ключевое слово let в функциональности области видимости блока. Итак, давайте посмотрим, чем они отличаются друг от друга.

Когда мы объявляем переменную как const, она считается постоянной переменной, значение которой никогда не изменится.

В случае let мы можем позже присвоить этой переменной новое значение следующим образом:

let number = 10;
number = 20;
console.log(number); // 20

Но мы не можем этого сделать в случае const

const number = 10;
number = 20; // Uncaught TypeError: Assignment to constant variable.

Мы даже не можем повторно объявить const переменную.

const number = 20;
console.log(number); // 20
const number = 10; // Uncaught SyntaxError: Identifier 'number' has already been declared

Теперь взгляните на приведенный ниже код:

const arr = [1, 2, 3, 4];
arr.push(5);
console.log(arr); // [1, 2, 3, 4, 5]

Мы сказали, что переменная const является константой, значение которой никогда не изменится, но мы изменили массив констант выше. Так разве это не наоборот?

Нет. Массивы являются ссылочными типами, а не примитивными типами в JavaScript

Таким образом, в arr сохраняется не фактический массив, а только ссылка (адрес) области памяти, где хранится фактический массив.

Таким образом, выполняя arr.push(5);, мы фактически не меняем ссылку, на которую указывает arr, но мы изменяем значения, хранящиеся в этой ссылке.

То же самое и с объектами:

const obj = {
 name: 'David',
 age: 30
};
obj.age = 40;
console.log(obj); // { name: 'David', age: 40 }

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

const obj = { name: 'David', age: 30 };
const obj1 = { name: 'Mike', age: 40 };
obj = obj1; // Uncaught TypeError: Assignment to constant variable.

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

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

Таким образом, приведенный ниже код недействителен, потому что мы повторно присваиваем ему новое значение.

const arr = [1, 2, 3, 4];
arr = [10, 20, 30]; // Uncaught TypeError: Assignment to constant variable.

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

Следующий код переопределения переменной const также недопустим.

const name = "David";
const name = "Raj"; // Uncaught SyntaxError: Identifier 'name' has already been declared

Заключение

  • Ключевые слова let и const добавляют область видимости блока в JavaScript.
  • Когда мы объявляем переменную как let, мы не можем re-define или re-declare другую let-переменную с тем же именем в той же области (области функции или блока), но мы можем re-assign ее значение.
  • Когда мы объявляем переменную как const, мы не можем re-define или re-declare другую const переменную с тем же именем в той же области (области функции или блока), но мы можем изменить значения, хранящиеся в этой переменной, если переменная имеет ссылочный тип, например массив или объект.

Синтаксис импорта и экспорта ES6

До того, как появился ES6, у нас было несколько тегов script в одном HTML-файле для импорта различных файлов javascript, например:

<script type="text/javascript" src="home.js"></script>
<script type="text/javascript" src="profile.js"></script>
<script type="text/javascript" src="user.js"></script>

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

ES6 исправил эту проблему с концепцией модулей.

Каждый файл javascript, который мы пишем в ES6, известен как модуль, и переменные и функции, которые мы объявляем в каждом файле, недоступны для других файлов, пока мы специально не экспортируем их из этого файла и не импортируем в другой файл.

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

Есть два типа экспорта:

  • Именованный экспорт: в одном файле может быть несколько именованных экспортов.
  • Экспорт по умолчанию: в одном файле может быть только один экспорт по умолчанию.

Именованный экспорт

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

export const temp = "This is some dummy text";

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

const temp1 = "This is some dummy text1";
const temp2 = "This is some dummy text2";
export { temp1, temp2 };

Обратите внимание, что синтаксис экспорта не является синтаксисом объектного литерала. Итак, в ES6 для экспорта чего-либо мы не можем использовать такие пары ключ-значение:

// This is invalid syntax of export in ES6
export { key1: value1, key2: value2 }

Чтобы импортировать то, что мы экспортировали как именованный экспорт, мы используем следующий синтаксис:

import { temp1, temp2 } from './filename';

Обратите внимание: при импорте чего-либо из файла нам не нужно добавлять расширение .js к имени файла, поскольку оно считается по умолчанию.

// import from functions.js file from current directory 
import { temp1, temp2 } from './functions';
// import from functions.js file from parent of current directory
import { temp1 } from '../functions';

Демо Codesandbox: https://codesandbox.io/s/hardcore-pond-q4cjx

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

Итак, если вы экспортируете как:

// constants.js
export const PI = 3.14159;

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

import { PI } from './constants';

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

import { PiValue } from './constants'; // This will throw an error

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

import { PI as PIValue } from './constants';

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

Мы также можем использовать синтаксис переименования во время экспорта:

// constants.js
const PI = 3.14159; 
export { PI as PIValue };

тогда при импорте мы должны использовать PIValue вот так:

import { PIValue } from './constants';

Чтобы экспортировать что-либо как именованный экспорт, мы должны сначала объявить это.

export 'hello'; // this will result in error
export const greeting = 'hello'; // this will work
export { name: 'David' }; // This will result in error
export const object = { name: 'David' }; // This will work

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

Взгляните на файл validations.js ниже.

// utils/validations.js
const isValidEmail = function(email) {
if (/^[^@ ]+@[^@ ]+\.[^@ \.]{2,}$/.test(email)) {
    return "email is valid";
  } else {
    return "email is invalid";
  }
};
const isValidPhone = function(phone) {
if (/^[\\(]\d{3}[\\)]\s\d{3}-\d{4}$/.test(phone)) {
    return "phone number is valid";
  } else {
    return "phone number is invalid";
  }
};
function isEmpty(value) { if (/^\s*$/.test(value)) {
    return "string is empty or contains only spaces";
  } else {
    return "string is not empty and does not contain
spaces";
  } 
}
export { isValidEmail, isValidPhone, isEmpty };

и в index.js мы используем эти функции, как показано ниже:

// index.js
import { isEmpty, isValidEmail } from "./utils/validations";
console.log("isEmpty:", isEmpty("abcd")); // isEmpty: string is not empty and does not contain spaces
console.log("isValidEmail:", isValidEmail("[email protected]")); // isValidEmail: email is valid
console.log("isValidEmail:", isValidEmail("ab@[email protected]")); // isValidEmail: email is invalid

Демо Codesandbox: https://codesandbox.io/s/youthful-flower-xesus

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

Экспорт по умолчанию

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

Однако вы можете объединить несколько именованных экспортов и один экспорт по умолчанию в одном файле.

Чтобы объявить экспорт по умолчанию, мы добавляем ключевое слово по умолчанию перед ключевым словом экспорта следующим образом:

//constants.js
const name = 'David'; 
export default name;

Чтобы импортировать экспорт по умолчанию, мы не добавляем фигурные скобки, как это было в именованном экспорте, например:

import name from './constants';

Если у нас есть несколько именованных экспортов и один экспорт по умолчанию, например:

// constants.js
export const PI = 3.14159; 
export const AGE = 30;
const NAME = "David";
export default NAME;

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

// NAME is default export and PI and AGE are named exports here
import NAME, { PI, AGE } from './constants';

Особенностью экспорта по умолчанию является то, что мы можем изменить имя экспортируемой переменной во время импорта:

// constants.js
const AGE = 30;
export default AGE;

А в другом файле мы можем использовать другое имя при импорте

import myAge from ‘./constants’; 
console.log(myAge); // 30

Здесь мы изменили имя экспортируемой переменной по умолчанию с AGE на myAge.

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

Еще одна вещь, на которую следует обратить внимание при экспорте по умолчанию, заключается в том, что ключевое слово экспорта по умолчанию не может предшествовать объявлению переменной следующим образом:

// constants.js
export default const AGE = 30; // This is an error and will not work

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

// constants.js 
const AGE = 30; 
export default AGE;

Однако мы можем экспортировать значение по умолчанию, не объявляя переменную следующим образом:

//constants.js
export default {
 name: "Billy",
 age: 40
};

а в другом файле используйте это так:

import user from './constants';
console.log(user.name); // Billy 
console.log(user.age); // 40

Существует еще один способ импорта всех переменных, экспортированных в файл, с использованием следующего синтаксиса:

import * as constants from './constants';

Здесь мы импортируем весь именованный экспорт и экспорт по умолчанию, который есть в constants.js и хранится в переменной constants. Итак, constants теперь станет объектом.

// constants.js
export const USERNAME = "David";
export default {
 name: "Billy",
 age: 40
};

а в другом файле мы используем его, как показано ниже:

// test.js
import * as constants from './constants';
console.log(constants.USERNAME); // David
console.log(constants.default); // { name: "Billy", age: 40 }
console.log(constants.default.age); // 40

Демо Codesandbox: https://codesandbox.io/s/green-hill-dj43b

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

// constants.js
const PI = 3.14159; const AGE = 30;
const USERNAME = "David";
const USER = {
 name: "Billy",
 age: 40 
};
export { PI, AGE, USERNAME, USER as default };

Здесь мы экспортируем USER как экспорт по умолчанию, а другие как именованный экспорт.

В другом файле вы можете использовать это так:

import USER, { PI, AGE, USERNAME } from "./constants";

Демо Codesandbox: https://codesandbox.io/s/eloquent-northcutt-7btp1

Заключение

  1. В ES6 данные, объявленные в одном файле, недоступны для другого файла, пока они не будут экспортированы из этого файла и импортированы в другой файл.
  2. Если у нас есть одна вещь в файле для экспорта, например, объявление класса, мы используем экспорт по умолчанию, в противном случае мы используем именованный экспорт. Мы также можем объединить экспорт по умолчанию и именованный экспорт в один файл.

Параметры по умолчанию

ES6 добавил довольно полезную функцию предоставления параметров по умолчанию при определении функций.

Предположим, у нас есть приложение, в котором после входа пользователя в систему мы показываем ему приветственное сообщение, подобное этому:

function showMessage(firstName) {
  return "Welcome back, " + firstName;
}
console.log(showMessage('John')); // Welcome back, John

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

Поэтому сначала нам нужно проверить, предоставляется ли firstName, а затем отобразить соответствующее сообщение. До ES6 мы должны были писать такой код:

function showMessage(firstName) {
  if(firstName) {
    return "Welcome back, " + firstName;
  } else {
    return "Welcome back, Guest";
  }
}
console.log(showMessage('John')); // Welcome back, John 
console.log(showMessage()); // Welcome back, Guest

Но теперь в ES6, используя параметры функции по умолчанию, мы можем написать приведенный выше код, как показано ниже:

function showMessage(firstName = 'Guest') {
   return "Welcome back, " + firstName;
}
console.log(showMessage('John')); // Welcome back, John 
console.log(showMessage()); // Welcome back, Guest

Мы можем присвоить параметру функции любое значение по умолчанию.

function display(a = 10, b = 20, c = b) { 
 console.log(a, b, c);
}
display(); // 10 20 20
display(40); // 40 20 20
display(1, 70); // 1 70 70
display(1, 30, 70); // 1 30 70

Как видите, мы присвоили уникальные значения параметрам функций a и b, но для c мы присваиваем значение b. Таким образом, любое значение, которое мы предоставили для b, будет присвоено c также, если для c не указано конкретное значение при вызове функции.

В приведенном выше коде мы не предоставили все аргументы функции. Таким образом, приведенные выше вызовы функций будут такими же, как показано ниже:

display(); // is same as display(undefined, undefined, undefined)
display(40); // is same as display(40, undefined, undefined)
display(1, 70); // is same as display(1, 70, undefined)

Таким образом, если передан аргумент undefined, для соответствующего параметра будет использоваться значение по умолчанию.

Мы также можем назначить сложное или вычисленное значение в качестве значения по умолчанию.

const defaultUser = {
  name: 'Jane',
  location: 'NY',
  job: 'Software Developer'
};
const display = (user = defaultUser, age = 60 / 2 ) => { 
 console.log(user, age);
};
display();
/* output
{
  name: 'Jane',
  location: 'NY',
  job: 'Software Developer'
} 30 
*/

Теперь взгляните на приведенный ниже код ES5:

// ES5 Code
function getUsers(page, results, gender, nationality) {
  var params = "";
  if(page === 0 || page) {
   params += `page=${page}&`; 
  }
  if(results) {
   params += `results=${results}&`;
  }
  if(gender) {
   params += `gender=${gender}&`;
  }
  if(nationality) {
   params += `nationality=${nationality}`;
  }
  fetch('https://randomuser.me/api/?' + params) 
   .then(function(response) {
     return response.json(); 
   })
   .then(function(result) { 
    console.log(result);
   }) 
   .catch(function(error) {
     console.log('error', error); 
   }); 
}
getUsers(0, 10, 'male', 'us');

В этом коде мы вызываем API Случайный пользователь, передавая различные необязательные параметры в функцию getUsers.

Поэтому перед вызовом API мы добавили различные условия if, чтобы проверить, добавлен ли параметр, и на основе этого строим строку запроса следующим образом: https://randomuser.me/api/? page=0&results=10&gender=male&nationality=us

Но вместо добавления такого количества условий if мы можем использовать параметры по умолчанию при определении параметров функции, как показано ниже:

function getUsers(page = 0, results = 10, gender = 'male',nationality = 'us') {
 fetch(`https://randomuser.me/api/?page=${page}&results=${results}&gender=${gender}&nationality=${nationality}`)
 .then(function(response) { 
  return response.json();
 }) 
 .then(function(result) {
   console.log(result); 
 })
 .catch(function(error) { 
  console.log('error', error);
  }); 
}
getUsers();

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

getUsers(1, 20, 'female', 'gb');

Таким образом, он переопределит параметры функции по умолчанию.

null не равно undefined

Но вы должны помнить об одном: null и undefined - это две разные вещи при определении параметров по умолчанию.

Взгляните на приведенный ниже код:

function display(name = 'David', age = 35, location = 'NY'){
 console.log(name, age, location); 
}
display('David', 35); // David 35 NY
display('David', 35, undefined); // David 35 NY

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

display('David', 35, undefined); // David 35 NY
display('David', 35, null); // David 35 null

Когда мы передаем null в качестве аргумента, мы специально указываем присвоить значение null параметру location, который не совпадает с undefined, поэтому он не будет принимать значение по умолчанию NY.

Array.prototype.includes

ES7 добавил метод includes, который проверяет, присутствует ли элемент в массиве или нет, и возвращает логическое значение либо true, либо false.

// ES5 Code
const numbers = ["one", "two", "three", "four"];
console.log(numbers.indexOf("one") > -1); // true
console.log(numbers.indexOf("five") > -1); // false

Тот же код, использующий метод Array includes, можно записать, как показано ниже:

// ES7 Code
const numbers = ["one", "two", "three", "four"];
console.log(numbers.includes("one")); // true
console.log(numbers.includes("five")); // false

Таким образом, использование методов Array includes делает код коротким и легким для понимания.

Метод includes также пригодится при сравнении с разными значениями.

Взгляните на приведенный ниже код:

const day = "monday";
if(day === "monday" || day === "tuesday" || day === "wednesday") {
  // do something
}

Приведенный выше код с использованием метода includes можно упростить, как показано ниже:

const day = "monday";
if(["monday", "tuesday", "wednesday"].includes(day)) {
  // do something
}

Таким образом, метод includes очень удобен при проверке значений в массиве.

Точки закрытия

Это был всего лишь предварительный просмотр некоторых вещей из руководства Освоение современного JavaScript.

Книга Освоение современного JavaScript охватывает все, что вам нужно знать, чтобы стать экспертом в навыках современного JavaScript.

При единовременной покупке вы будете получать обновленную копию книги бесплатно для каждого нового выпуска ESNext.

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

Это единственное руководство, которое вам нужно, чтобы пройти любое собеседование по JavaScript / React, где функции ES6 + являются необходимыми вещами для взлома интервью.

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

Хотите быть в курсе регулярного контента по JavaScript, React, Node.js? Следуй за мной в LinkedIn.

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