Станьте экспертом в современном 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
Заключение
- В ES6 данные, объявленные в одном файле, недоступны для другого файла, пока они не будут экспортированы из этого файла и импортированы в другой файл.
- Если у нас есть одна вещь в файле для экспорта, например, объявление класса, мы используем экспорт по умолчанию, в противном случае мы используем именованный экспорт. Мы также можем объединить экспорт по умолчанию и именованный экспорт в один файл.
Параметры по умолчанию
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.
Не забудьте подписаться, чтобы получать мою еженедельную рассылку с замечательными советами, приемами и статьями прямо в свой почтовый ящик здесь.