[Перевод] Советы ES6, как сделать ваш код короче, чище и читабельнее

JavaScript ECMAScript 6

Советы по ES6, чтобы сделать ваш код короче, чище и читабельнее

напишите перед статьей

Эта статья переведена сES6 tips and tricks to make your code cleaner, shorter, and easier to read!В статье резюмируется es6 с точки зрения чистоты кода. Пожалуйста, укажите на ошибки.

шаблонные литералы шаблонные строки

Строки-шаблоны делают работу со строками проще, чем когда-либо, они начинаются с обратной кавычки (`) и могут использоваться с${变量}для вставки переменных. Давайте сравним следующие две строки кода.

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 использует область действия функции, поэтому мы все чаще используем выражения анонимных непосредственных функций (iife) для инкапсуляции целых файлов JavaScript. Мы делаем это, чтобы изолировать все переменные в файле, чтобы избежать конфликтов переменных.

Теперь у нас есть объявления переменных с блочной областью видимости и два совершенно новых объявления переменных с блочной областью видимости.

letкоманда объявления let

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

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

Поскольку он ограничен областью действия на уровне блоков, он решил очень классический вопрос интервью: «Каков вывод следующего кода и как я могу изменить его, чтобы он выглядел так, как вы хотите, чтобы он выполнялся?»

for (var i = 1; i < 5; i++){
    setTimeout(() => { 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

Const

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

теперь у нас естьconstЗаказ.

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что бы ни было в состоянии. но теперь мы получим выводReferenceError, потому чтоbazВсегда ограничивается областью действия на уровне блоков.

Оператор спреда

Представлен ES6...оператор, этот оператор относится к «оператору спреда». У него два основных применения: 1. Поместить массив или объект в новый массив или объект 2. Объединить несколько параметров в массиве вместе

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

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

Объект также может быть расширен, что записывает каждую пару ключ-значение в новый объект. (Расширения объектов уже находятся на четвертом этапе предложения и будут официально доступны в es2018. Но в настоящее время эта функция поддерживается только в Chrome 60 и более поздних версиях, Firefox 55 и более поздних версиях и Node 6.4.0 и более поздних версиях.) Примечание. вes2018 в блоге 2alityВ статье мы узнали, что на только что завершившейся конференции TC39 были доработаны характеристики ECMA2018. 】

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] 不同的数组
c.push(5);
console.log(a);  // [1, 2, 3, 5] 
console.log(c);  // [1, 2, 3, 5] 同一个数组

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

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

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

Функции теперь могут быть определены со значениями параметров по умолчанию. Никакие параметры или неопределенные значения не инициализируются значениями по умолчанию. Но следует отметить, что и null, и false будут сведены к 0.

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

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

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 ]

Разрушение

Деструктуризация — это процесс разделения массива или объекта слева от знака равенства. Этот массив или объект может быть получен из переменной, функции или уравнения.

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

Структура типа объекта, ключи объекта могут быть перечислены в фигурных скобках для извлечения пар ключ-значение.

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

Иногда вам может понадобиться извлечь значение и присвоить его новой переменной, что можно сделать, используя «ключ: переменная» слева от знака равенства.

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. 

Кроме того, структура объекта позволяет присваивать несколько переменных.

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

Краткое представление литералов и свойств объектов

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

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}

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

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

Краткая нотация также может использоваться для деструктуризации объекта и передачи его в функцию. Методы 1 и 2 — это то, как вы делали это до es6, а метод 3 — использовать деструктурирование и краткие выражения.

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

Используя ES6, мы можем извлечьage,name,а такжеcompany, без каких-либо других объявлений переменных.

Имя динамического свойства

В ES6 добавлена ​​возможность создавать или добавлять свойства с динамически назначаемыми ключами.

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

стрелочная функция

Стрелочные функции имеют еще две важные особенности: их структуру и ихthisнаправление

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

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

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

Одно из наиболее важных применений стрелочных функций — в функциях, связанных с массивами, например.map,.forEach,.sortи т.п.

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

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

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

Это назначение должно быть выполнено, потому что привязка this является динамической. Это означает, что this внутри eventlistener не ссылается на то же самое внутри doSomething.

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

Хотя эта лексика это здорово, иногда это не то, что мы хотим.

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

когда мы используемa.oneThing(6), этоthis.otherThing(6)выдаст ошибку с ошибкой ссылки, потому чтоthisнет указателя на объектa, но указывает на область окружения. Если вы используете код ES6 с синтаксисом ES6, вам нужно знать об этом.

для... петель (для... петель)

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

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

использовать новыйfor ... ofпетли, внутри каждой петли сохраняетсяlet val = a[idx].

Массивы, строки, генераторы и коллекции в стандартном JavaScript поддерживают итерацию. Обычные объекты нельзя перебирать, как обычно, используя for...of, если только вы сами не определите итератор.

Числовые литералы

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

ES6 добавил новый формат, добавив o после начального 0, чтобы объявить восьмеричное число. В то же время в es6 также был добавлен бинарный формат.

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

Более

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

Если не терпится, прочтите Кайла Симпсона.YOU DONT KNOW JAVASCRIPT ON ES6, или взгляните на этоклассный маленький сайт