Поради та підказки ES6, щоб зробити ваш код чистішим, коротшим та легшим для читання!

Поради та підказки ES6, щоб зробити ваш код чистішим, коротшим та легшим для читання!

Шаблонні літерали

Шаблонні літерали роблять роботу зі рядками набагато простішою, ніж раніше. Вони починаються із зворотного позначки і можуть містити змінні за допомогою ${variable}. Порівняйте ці два рядки коду:

var fName = 'Peter', sName = 'Smith', age = 43, job= 'photographer';var a = 'Hi, I\'m ' + fName + ' ' + sName + ', I\'m ' + age + ' and work as a ' + job + '.';var b = `Hi, I'm ${ fName } ${ sName }, I'm ${ age } and work as a ${ job }.`;

Це робить життя набагато простішим, а код легшим для читання. В фігурні дужки можна вставити що завгодно: змінні, рівняння або виклики функцій. Я буду використовувати їх у прикладах цієї статті.

Обсяг блоків синтаксису

JavaScript завжди був визначений функціями, саме тому стало загальним обертати весь файл JavaScript у порожній вираз функції, що викликається одразу (IIFE). Це робиться для ізоляції всіх змінних у файлі, щоб не було конфліктів змінних.

Тепер у нас є масштаб блоку та два нові оголошення змінних, які прив’язані до блоку.

Декларація "Нехай"

Це схоже на, varале має кілька помітних відмінностей. Оскільки це область блоку, нову змінну з тим самим іменем можна оголосити, не впливаючи на зовнішні змінні.

var a = 'car' ;{ let a = 5; console.log(a) // 5}console.log(a) // car

Оскільки він прив’язаний до блоку, він вирішує це класичне запитання щодо інтерв’ю:

"що таке результат і як ви змусите його працювати так, як ви очікуєте?"

for (var i = 1; i  { console.log(i); }, 1000);}

У цьому випадку він виводить "5 5 5 5 5", оскільки змінна i змінюється на кожній ітерації.

Якщо ви вимкнете varдля, letтоді все зміниться. Тепер кожен цикл створює нову область блоку зі значенням i, прив'язаним до цього циклу. Хоча ви написали:

{let i = 1; setTimeout(() => { console.log(i) }, 1000)} {let i = 2; setTimeout(() => { console.log(i) }, 1000)} {let i = 3; setTimeout(() => { console.log(i) }, 1000)} {let i = 4; setTimeout(() => { console.log(i) }, 1000)} {let i = 5; setTimeout(() => { console.log(i) }, 1000)} 

Ще одна відмінність між varі letполягає в тому, що letвоно не піднімається як varє.

{ console.log(a); // undefined console.log(b); // ReferenceError var a = 'car'; let b = 5;}

Через його більш жорсткий обсяг та більш передбачувану поведінку, деякі люди сказали, що ви повинні використовувати letзамість цього var, за винятком випадків, коли вам спеціально потрібен підйом або більш вільний обсяг varдекларації.

Конст

Якщо ви раніше хотіли оголосити константу змінної в JavaScript, було прийнято називати змінну в заголовках. Однак це не забезпечить змінну - це просто дасть зрозуміти іншим розробникам, що вона є константою і не повинна змінюватися.

Тепер ми маємо constдекларацію.

{ const c = "tree"; console.log(c); // tree c = 46; // TypeError! }

constне робить змінну незмінною, просто блокує її призначення. Якщо у вас є складне присвоєння (об'єкт або масив), тоді значення все ще можна змінити.

{ const d = [1, 2, 3, 4]; const dave = { name: 'David Jones', age: 32}; d.push(5); dave.job = "salesman"; console.log(d); // [1, 2, 3, 4, 5] console.log(dave); // { age: 32, job: "salesman", name: 'David Jones'}}

Проблема з функціями масштабування блоків

Оголошення функцій тепер вказані для прив'язки до блокування масштабу.

{ bar(); // works function bar() { /* do something */ }}bar(); // doesn't work

Проблема виникає, коли ви оголошуєте функцію всередині ifоператора.

Розглянемо це:

if ( something) { function baz() { console.log('I passed') }} else { function baz() { console.log('I didn\'t pass') } } baz();

До ES6 обидва оголошення функції були б підняті, і результат був би 'I didn\'t pass'незалежно від того, що somethingбуло.

Тепер ми отримуємо 'ReferenceError', як bazзавжди пов'язано з обсягом блоку.

Поширення

ES6 вводить ...оператора, який називається "оператором розповсюдження". Він має два основних способи використання: розповсюдження масиву або об’єкта в новий масив чи об’єкт та об’єднання кількох параметрів у масив.

Перший варіант використання - це той, який ви, мабуть, найчастіше зустрінете, тому ми розглянемо його спочатку.

let a = [3, 4, 5];let b = [1, 2, ...a, 6];console.log(b); // [1, 2, 3, 4, 5, 6]

Це може бути дуже корисним для передачі набору змінних функції у масив.

function foo(a, b, c) { console.log(`a=${a}, b=${b}, c=${c}`)} let data = [5, 15, 2];foo( ...data); // a=5, b=15, c=2

Об'єкт також можна розповсюджувати, вводячи кожну з пар значень ключа в новий об'єкт. (Розповсюдження об’єктів фактично знаходиться на стадії 4 пропозиції та буде офіційно в ES2018. Його підтримує лише Chrome 60 або новіша версія, Firefox 55 або новіша версія та Node 6.4.0 або новіша версія)

let car = { type: 'vehicle ', wheels: 4};let fordGt = { make: 'Ford', ...car, model: 'GT'};console.log(fordGt); // {make: 'Ford', model: 'GT', type: 'vehicle', wheels: 4}

Ще однією особливістю оператора поширення є те, що він створює новий масив або об’єкт. Наведений нижче приклад створює новий масив для b, але cпросто посилається на той самий масив.

let a = [1, 2, 3];let b = [ ...a ];let c = a;b.push(4);console.log(a); // [1, 2, 3]console.log(b); // [1, 2, 3, 4] referencing different arraysc.push(5);console.log(a); // [1, 2, 3, 5] console.log(c); // [1, 2, 3, 5] referencing the same array

Другий варіант використання - це збір змінних у масив. Це дуже корисно, коли ви не знаєте, скільки змінних передається функції.

function foo(...args) { console.log(args); } foo( 'car', 54, 'tree'); // [ 'car', 54, 'tree' ] 

Параметри за замовчуванням

Функції тепер можна визначати за допомогою параметрів за замовчуванням. Відсутні або невизначені значення ініціалізуються значенням за замовчуванням. Тільки будьте обережні - бо нульові та помилкові значення примусові до 0.

function foo( a = 5, b = 10) { console.log( a + b);} foo(); // 15foo( 7, 12 ); // 19foo( undefined, 8 ); // 13foo( 8 ); // 18foo( null ); // 10 as null is coerced to 0

The default values can be more than just values — they can also be expressions or functions.

function foo( a ) { return a * 4; }function bar( x = 2, y = x + 4, z = foo(x)) { console.log([ x, y, z ]);}bar(); // [ 2, 6, 8 ]bar( 1, 2, 3 ); //[ 1, 2, 3 ] bar( 10, undefined, 3 ); // [ 10, 14, 3 ]

Destructuring

Destructuring is the process of taking apart the array or object on the left hand side of the equal sign. The array or object can come from a variable, function, or equation.

let [ a, b, c ] = [ 6, 2, 9];console.log(`a=${a}, b=${b}, c=${c}`); //a=6, b=2, c=9
function foo() { return ['car', 'dog', 6 ]; } let [ x, y, z ] = foo();console.log(`x=${x}, y=${y}, z=${z}`); // x=car, y=dog, z=6

With object destructuring, the keys of the object can be listed inside curly braces to extract that key-value pair.

function bar() { return {a: 1, b: 2, c: 3}; }let { a, c } = bar();console.log(a); // 1console.log(c); // 3console.log(b); // undefined

Sometimes, you want to extract the values but assign them to a new variable. This is done using a 'key: variable' pairing on the left of the equals sign.

function baz() { return { x: 'car', y: 'London', z: { name: 'John', age: 21} }; }let { x: vehicle, y: city, z: { name: driver } } = baz();
console.log( `I'm going to ${city} with ${driver} in their ${vehicle}.`); // I'm going to London with John in their car. 

Another thing that object destructuring allows is assigning a value to multiple variables.

let { x: first, x: second } = { x: 4 };console.log( first, second ); // 4, 4

Object Literals and Concise Parameters

When you are creating an object literal from variables, ES6 allows you to omit the key if it is the same as the variable name.

let a = 4, b = 7;let c = { a: a, b: b };let concise = { a, b };console.log(c, concise) // {a: 4, b: 7}, {a: 4, b: 7}

This can also be used in combination with destructuring to make your code much simpler and cleaner.

function foo() { return { name: 'Anna', age: 56, job: { company: 'Tesco', title: 'Manager' } };} 
// pre ES6let a = foo(), name = a.name, age = a.age, company = a.job.company;
// ES6 destructuring and concise parameters let { name, age, job: {company}} = foo();

It can also be used to destructure objects passed into functions. Method 1 and 2 are how you would have done it before ES6, and method 3 uses destructuring and concise parameters.

let person = { name: 'Anna', age: 56, job: { company: 'Tesco', title: 'Manager' }};
// method 1function old1( person) { var yearOfBirth = 2018 - person.age; console.log( `${ person.name } works at ${ person.job.company } and was born in ${ yearOfBirth }.`);}
// method 2function old1( person) { var age = person.age, yearOfBirth = 2018 - age, name = person.name, company = person.job.company; console.log( `${ name } works at ${ company } and was born in ${ yearOfBirth }.`);} 
// method 3function es6({ age, name, job: {company}}) { var yearOfBirth = 2018 - age; console.log( `${ name } works at ${ company } and was born in ${ yearOfBirth }.`);} 

Using ES6, we can extract the age, name and company without extra variable declaration.

Dynamic Property Names

ES6 adds the ability to create or add properties with dynamically assigned keys.

let city= 'sheffield_';let a = { [ city + 'population' ]: 350000};a[ city + 'county' ] = 'South Yorkshire';console.log(a); // {sheffield_population: 350000, sheffield_county: 'South Yorkshire' }

Arrow Functions

Arrow functions have two main aspects: their structure and their this binding.

They can have a much simpler structure than traditional functions because they don't need the function key word, and they automatically return whatever is after the arrow.

var foo = function( a, b ) { return a * b;} 
let bar = ( a, b ) => a * b;

If the function requires more than a simple calculation, curly braces can be used and the function returns whatever is returned from the block scope.

let baz = ( c, d ) => { let length = c.length + d.toString().length; let e = c.join(', '); return `${e} and there is a total length of ${length}`;}

One of the most useful places for arrow functions is in array functions like .map, .forEach or .sort.

let arr = [ 5, 6, 7, 8, 'a' ];let b = arr.map( item => item + 3 );console.log(b); // [ 8, 9, 10, 11, 'a3' ]

As well as having a shorter syntax, it also fixes the issues that often arose around the this binding behaviour. The fix with pre-ES6 functions was to store the this reference, often as a self variable.

var clickController = { doSomething: function (..) { var self = this; btn.addEventListener( 'click', function() { self.doSomething(..) }, false ); } };

This had to be done because the this binding is dynamic. This means that the this inside the event listener and the this inside the doSomething do not refer to the same thing.

Inside arrow functions, the this binding is lexical, not dynamic. This was the main design feature of the arrow function.

Whilst lexical this binding can be great, sometimes that's not what is wanted.

let a = { oneThing: ( a ) => { let b = a * 2; this.otherThing(b); }, otherThing: ( b ) => {....} };
a.oneThing(6);

When we use a.oneThing(6), the this.otherThing( b ) reference fails as this doesn't point to the a object, but to the surrounding scope. If you are rewriting legacy code using ES6 syntax, this is something to watch out for.

for … of Loops

ES6 adds a way to iterate over each of the values in an array. This is different from the existing for ... in loop that loops over the key/index.

let a = ['a', 'b', 'c', 'd' ];// ES6 for ( var val of a ) { console.log( val );} // "a" "b" "c" "d"// pre-ES6 for ( var idx in a ) { console.log( idx );} // 0 1 2 3

Using the new for … of loop saves adding a let val = a[idx] inside each loop.

Arrays, strings, generators and collections are all iterable in standard JavaScript. Plain objects can't normally be iterated over, unless you have defined an iterator for it.

Number Literals

ES5 code handled decimal and hexadecimal number formats well, but octal form wasn't specified. In fact, it was actively disallowed in strict mode.

ES6 has added a new format, adding an o after the initial 0 to declare the number an octal. They've also added a binary format.

Number( 29 ) // 29Number( 035 ) // 35 in old octal form. Number( 0o35 ) // 29 in new octal form Number( 0x1d ) // 29 in hexadecimal Number( 0b11101 ) // 29 in binary form

And Much More…

There is much, much more that ES6 offers us to make our code cleaner, shorter, easier to read and more robust. I aim to write a continuation of this article covering the less well known bits of ES6.

If you can’t wait that long, have a read of Kyle Simpson’s You Don’t Know JS book on ES6, or check out this brilliant little website!

Do you want to become a developer and get your first software job? Download the 7 Steps to Becoming a Developer and Getting Your First Job.

ДАЛІ далі -> Як захистити роботу своєї мрії. Опануйте процес співбесіди

Якщо вам сподобалось це і ви вважаєте корисним, покажіть свою підтримку, поплескавши, і підпишіться, щоб отримати більше статей, подібних до цієї!