Skip to content

Instantly share code, notes, and snippets.

@nikneroz
Last active March 13, 2018 10:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nikneroz/baed5220c848c82323c1676fcb7f3e4f to your computer and use it in GitHub Desktop.
Save nikneroz/baed5220c848c82323c1676fcb7f3e4f to your computer and use it in GitHub Desktop.
ES6 overview

ES6

В ECMAScript поддерживаются пять примитивных типов данных:

  • Number
  • String
  • Boolean
  • Null
  • Undefined
  • Object

Объявление переменных

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

Область видимости переменной let – блок {...}.

Замена var на var

var apples = 5;

if (true) {
  var apples = 10;

  alert(apples); // 10 (внутри блока)
}

alert(apples); // 10 (снаружи блока то же самое)

Замена let на var

let apples = 5; // (*)

if (true) {
  let apples = 10;

  alert(apples); // 10 (внутри блока)
}

alert(apples); // 5 (снаружи блока значение не изменилось)

Область видимости переменной const

const apple = 5;
apple = 10; // ошибка
const user = {
  name: "Вася"
};

user.name = "Петя"; // допустимо
user = 5; // нельзя, будет ошибка

Блоки и область видимости

Что такое область видимости?

В JS область видимости – это текущий контекст в коде. ОВ могут быть определены локально или глобально. Ключ к написанию пуленепробиваемого кода – понимание ОВ. Давайте разбираться, где переменные и функции доступны, как менять контекст в коде и писать более быстрый и поддерживаемый код (который и отлаживать быстрее). Разбираться с ОВ просто – задаём себе вопрос, в какой из ОВ мы сейчас находимся, в А или в Б?

// ОВ A: глобальная
var myFunction = function () {
  // ОВ B: локальная
};

Глобальная область видимости

// глобальная ОВ
var name = 'Todd';

Локальная область видимости

var myFunction = function () {
  var name = 'Todd';
  console.log(name); // Todd
};

console.log(name); // ReferenceError: name is not defined

Лексическая область видимости

var myFunction = function () {
  var name = 'Todd';
  var myOtherFunction = function () {
    console.log('My name is ' + name);
  };
  console.log(name); // `Todd`
  myOtherFunction(); // `My name is Todd`
};

Приватная

(function () {
  // здесь приватная ОВ
})();

Пример:

(function () {
  var myFunction = function () {
    // делаем здесь, что нужно
  };
})();
myFunction(); // Uncaught ReferenceError: myFunction is not defined

Публичная

var Module = (function () {
  var privateMethod = function () {

  };
  return {
    publicMethod: function () {

    }
  };
})();

Как работает this?

Каждая ОВ назначает своё значение переменной this, в зависимости от способа вызова функции. Мы все использовали ключевое слово this, но не все понимают, как оно работает и какие есть отличия при вызовах. По умолчанию, оно относится к объекту самой внешней ОВ, текущему окну. Пример того, как разные вызовы меняют значения this:

Пример:

var myFunction = function () {
  console.log(this); // this = глобальное, [объект Window]
};
myFunction();

var myObject = {};
myObject.myMethod = function () {
  console.log(this); // this = текущий объект { myObject }
};

var nav = document.querySelector('.nav'); // <nav class="nav">
var toggleNav = function () {
  console.log(this); // this = элемент <nav> 
};
nav.addEventListener('click', toggleNav, false);

Меняем ОВ при помощи .call(), .apply() и .bind()

.bind()

var pokemon = {
    firstname: 'Pika',
    lastname: 'Chu ',
    getPokeName: function() {
        var fullname = this.firstname + ' ' + this.lastname;
        return fullname;
    }
};

var pokemonName = function() {
    console.log(this.getPokeName() + 'I choose you!');
};

var logPokemon = pokemonName.bind(pokemon); // creates new object and binds pokemon. 'this' of pokemon === pokemon now

logPokemon(); // 'Pika Chu I choose you!'

.call() & .apply()

var pokemon = {
    firstname: 'Pika',
    lastname: 'Chu ',
    getPokeName: function() {
        var fullname = this.firstname + ' ' + this.lastname;
        return fullname;
    }
};

var pokemonName = function(snack, hobby) {
    console.log(this.getPokeName() + ' loves ' + snack + ' and ' + hobby);
};

pokemonName.call(pokemon,'sushi', 'algorithms'); // Pika Chu  loves sushi and algorithms
pokemonName.apply(pokemon,['sushi', 'algorithms']); // Pika Chu  loves sushi and algorithms

Прототипирование

function getDog(name, age){
    return {
        "name": name,
        "age": age,
        "talk": function(){
            alert('Name: ' + this.name + ', Age: ' + this.age);
        }
    };
}
var rocky = getDog('Rocky', 5);
var jerry = getDog('Jerry', 3);
function Dog(name, age){
    this['name'] = name;
    this.age = age;
}
Dog.prototype = {
    "talk": function(){
        alert('Name: ' + this.name + ', Age: ' + this.age);
    }
};

var rocky = new Dog('Rocky', 5);
var jerry = new Dog('Jerry', 3);

Расширение с помощью прототипов.

Date.prototype.getDayName = function(){
    var days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
    return days[this.getDay()];
}
var today = new Date();
alert(today.getDayName());

Полифиллы

«Полифилл» (англ. polyfill) – это библиотека, которая добавляет в старые браузеры поддержку возможностей, которые в современных браузерах являются встроенными.

Один полифилл мы уже видели, когда изучали собственно JavaScript – это библиотека ES5 shim. Если её подключить, то в IE8- начинают работать многие возможности ES5. Работает она через модификацию стандартных объектов и их прототипов. Это типично для полифиллов.

Перегрузка функций - отсутствует

function sum(arg1, arg2) {
    return arg1 + arg2;
}

function sum(arg1, arg2, arg3) {
    return arg1 + arg2 + arg3;
}

alert(sum(3, 4));       // NaN
alert(sum(3, 4, 5));    // 12
function sum(arg1, arg2, arg3) {
    switch (typeof arg3) {
        case "undefined":
            return arg1 + arg2;
        case "number":
            return arg1 + arg2 + arg3;
        default:
            return arg1 + arg2 + " (" + arg3 + ")";
    }
}

alert(sum(3, 4));       // 7
alert(sum(3, 4, 5));    // 12
alert(sum(3, 4, "!"));  // "7 (!)"

Объекты в JavaScript и мутация

В JavaScript-объекты можно добавлять свойства. Когда это делают после создания экземпляра объекта, объект необратимо изменяется. В следующем примере константа egg, объект, мутирует после того, как к ней добавляют свойство isBroken. Такие объекты (вроде egg) мы называем мутабельными (то есть, имеющими возможность мутировать, изменяться).

const egg = { name: "Humpty Dumpty" };
egg.isBroken = false;

console.log(egg);
// {
//   name: "Humpty Dumpty",
//   isBroken: false
// }

Об опасности мутаций

Предположим, создана константа с именем newEgg, в которую записан объект egg. Затем понадобилось изменить свойство name у newEgg:

const egg = { name: "Humpty Dumpty" };

const newEgg = egg;
newEgg.name = "Errr ... Not Humpty Dumpty";

Объекты в JavaScript и ссылки на них

Для того чтобы осознать смысл утверждения «объекты передаются по ссылке», сначала нужно понять то, что у каждого объекта в JavaScript есть уникальный идентификатор. Когда вы назначаете объект переменной, вы связываете переменную с идентификатором этого объекта (то есть, переменная теперь ссылается на объект) вместо того, чтобы записывать в переменную значение объекта, копировать его. Именно поэтому, сравнивая два разных объекта, даже содержащих одни и те же значения (или не содержащих их вовсе), мы получаем false.

console.log({} === {}); // false

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

console.log(egg === newEgg); // true

Особенности операторов Javascript & ECMAScript

alert("NaN" == NaN);       // false
alert(NaN == NaN);         // false
alert(true == 1);          // true
alert(true == 42);         // false
alert(null == 0);          // false
alert(0 == "");            // true
alert("" == 0);            // true
alert("false" == false);   // false
alert(false == 0);         // true
alert(undefined == false); // false
alert(null == false);      // false
alert(undefined == null);  // true
alert(" \t\r\n " == 0);    // true

Функции обратного вызова- Callback функции

function sumOfResults(callback) {
    var result = 0;
    for (var i = 1; i < arguments.length; i++) {
        result += callback(arguments[i]);
    }
    return result;
}

var square = function(x) {
    return x * x;
};
alert(sumOfResults(square, 3, 4)); // 25

Замыкания

var uniqueId = function() {
    var id = 0;
    return function() { return id++; };
}();

var aValue = uniqueId();
var anotherValue = uniqueId();

Каррирование

Каррирование (от англ. currying, иногда — карринг) — преобразование функции от многих аргументов в набор функций, каждая из которых является функцией от одного аргумента.

var multNumber = function(arg) {
    return function(mul) {
        return arg * mul;
    };
};

var multFive = multNumber(5);
alert(multFive(7)); //35
 3  - 1  // -> 2
 3  + 1  // -> 4
'3' - 1  // -> 2
'3' + 1  // -> '31'

'' + '' // -> ''
[] + [] // -> ''
{} + [] // -> 0
[] + {} // -> '[object Object]'
{} + {} // -> '[object Object][object Object]'

'222' - -'111' // -> 333

[4] * [4]       // -> 16
[] * []         // -> 0
[4, 4] * [4, 4] // NaN

💡 Explanation:

Number  + Number  -> addition
Boolean + Number  -> addition
Boolean + Boolean -> addition
Number  + String  -> concatenation
String  + Boolean -> concatenation
String  + String  -> concatenation

ES6 Features

Pattern matching

let { first: f, last: l } = { first: 'Jane', last: 'Doe' };
console.log(f); // 'Jane'
console.log(l); // 'Doe'

Подходы к созданию объектов

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

  • Фабрика объектов: функция, создающая объект и возвращающая его в качестве своего значения,
  • Конструктор: функция: использующая ключевое слово this для формирования свойств объекта, создаваемого ей с помощью оператора new,
  • Прототипный подход: задействование свойства prototype функции для вынесения общих свойств объектов,

Классы

// Supertype
class Person {
   constructor(name) {
      this.name = name;
   }

   describe() {
      return "Person called " + this.name;
   }
}

// Subtype
class Employee extends Person {
   constructor(name, title) {
      super.constructor(name);
      this.title = title;
   }

   describe() {
      return super.describe() + " (" + this.title + ")";
   }
}


let jane = new Employee("Jane", "CTO");
jane instanceof Person; // true
jane instanceof Employee; // true
jane.describe(); // 'Person called Jane (CTO)'

Модули

module Math {
   export function sum(x, y) {
      return x + y;
   }

   export var pi = 3.141593;

   // Не видна снаружи
   function internal() {
      ...
   }
}

// Импортирование модуля:

import Math.{sum, pi}; 
alert("2π = " + sum(pi, pi));

Arrow-функции

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

let squares = [ 1, 2, 3 ].map(x => x * x);

// Код выше эквивалентен этому:

let squares = [ 1, 2, 3 ].map(function (x) { return x * x });

Spread_operator

[...iterableObj, 4, 5, 6]
[a, b, ...iterableObj] = [1, 2, 3, 4, 5];
var parts = ['плечи', 'колени'];
var lyrics = ['голова', ...parts, 'и', 'пальцы'];
// ["голова", "плечи", "колени", "и", "пальцы"]

Копирование массива
var arr = [1, 2, 3];
var arr2 = [...arr]; // like arr.slice()
arr2.push(4); 

// теперь arr2 содержит [1, 2, 3, 4]
// arr остается неизменным

А с использованием spread:
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
arr1 = [...arr1, ...arr2];

Spread в литералах объектов

var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };

var clonedObj = { ...obj1 };
// Object { foo: "bar", x: 42 }

var mergedObj = { ...obj1, ...obj2 };
// Object { foo: "baz", x: 42, y: 13 }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment