JS

function constructor

 Привязка контекста

Потеря this.

Мы уже видели примеры потери this. Как только метод передаётся отдельно от объекта – this теряется.

let user = {
  firstName: "Вася",
  sayHi() {
    console.log(`Привет, ${this.firstName}!`);
  }
};

setTimeout(user.sayHi, 1000); // Привет, undefined!

Метод setTimeout в браузере имеет особенность: он устанавливает this=window для вызова функции

Task

Исправьте код

let user = {
  firstName: "Вася",
  sayHi() {
    console.log(`Привет, ${this.firstName}!`);
  }
};

setTimeout(user.sayHi, 1000); // Привет, undefined!

Решение: Функция обертка

let user = {
  firstName: "Вася",
  sayHi() {
    console.log(`Привет, ${this.firstName}!`);
  }
};

setTimeout(function() {
  user.sayHi(); // Привет, Вася!
}, 1000);

 Привязка контекста

Функция обертка

let user = {
  firstName: "Вася",
  sayHi() {
    console.log(`Привет, ${this.firstName}!`);
  }
};

setTimeout(() => user.sayHi(), 1000); // Привет, Вася!

 Привязка контекста

Функция обертка

let user = {
  firstName: "Вася",
  sayHi() {
    console.log(`Привет, ${this.firstName}!`);
  }
};

setTimeout(() => user.sayHi(), 1000);

// ...в течение 1 секунды
user = { sayHi() { alert("Другой пользователь в 'setTimeout'!"); } };

// Другой пользователь в 'setTimeout'!

 Привязка контекста

В современном JavaScript у функций есть встроенный метод bind, который позволяет зафиксировать this.

let user = {
  firstName: "Вася"
};

function getName() {
  console.log(this.firstName);
}

let funcUser = getName.bind(user);
funcUser(); // Вася

bind

Здесь func.bind(user) – это «связанный вариант» func, с фиксированным this=user.

Сделайте так что бы при вызове метода sayHi вывелось имя Vic при помощи привязки контекста.

function sayHi() {
  console.log( this.name );
}

Task

Вызов checkPasswork() в приведённом ниже коде должен проверить пароль и затем вызвать user.loginOk/loginFail в зависимости от ответа.

Однако, его вызов приводит к ошибке. Почему?

function checkPassword(ok, fail) {
  let password = prompt("Password?", '');
  if (password === "javascript") ok();
  else fail();
}

let user = {
  name: 'Вася',

  loginOk() {
    console.log(`${this.name} logged in`);
  },

  loginFail() {
    console.log(`${this.name} failed to log in`);
  },

};

checkPassword(user.loginOk, user.loginFail);

Task

function showFullName() {
  console.log( this.firstName + " " + this.lastName );
}

let user = {
  firstName: "Василий",
  lastName: "Петров"
};

// функция вызовется с this=user
showFullName.call(user) // "Василий Петров"

call

Вызов func.call(context, a, b...) – то же, что обычный вызов func(a, b...), но с явно указанным this(=context).

func.call(context, arg1, arg2);
// идентичен вызову
func.apply(context, [arg1, arg2]);

apply

Вызов функции при помощи func.apply работает аналогично func.call, но принимает массив аргументов вместо списка.

function Animal(name) {
  this.name = name;
  this.canWalk = true;
}

let dog = new Animal("dog");

console.log(dog.name)

Function Constructor

Функции-конструкторы являются обычными функциями. Но есть два соглашения:

  1. Имя функции-конструктора должно начинаться с большой буквы.
  2. Функция-конструктор должна вызываться при помощи оператора "new".

Function Constructor

Когда функция вызывается как new Animal(...), происходит следующее:

  1. Создаётся новый пустой объект, и он присваивается this.
  2. Выполняется код функции. Обычно он модифицирует this, добавляет туда новые свойства.
  3. Возвращается значение this.

Другими словами, вызов new Animal(...) делает примерно вот что:

function Animal(name) {
  // 1. this = {};  (неявно)
  
  // 2. добавляет свойства к this
  this.name = name;
  this.canWalk = true;

  // 3. return this;  (неявно)
}

let dog = new Animal("dog");

console.log(dog)

Function Constructor

{
  name: "dog",
  canWalk: true,
}
function Animal(name) {
  // this = {};  (неявно)
  
  // добавляет свойства к this
  this.name = name;
  this.canWalk = true;

  // return this;  (неявно)
}

let dog = new Animal("dog");

console.log(dog.name)

Function Constructor

Function Constructor

Возврат значения

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

Но если return всё же есть, то применяется простое правило:

  • При вызове return с объектом, будет возвращён объект, а не this.
  • При вызове return с примитивным значением, примитивное значение будет отброшено.

Другими словами, return с объектом возвращает объект, в любом другом случае конструктор вернёт this.

Function Constructor

Создание методов

function User(name) {
  this.name = name;

  this.sayHi = function() {
    alert( "Меня зовут: " + this.name );
  };
}

let vasya = new User("Вася");

vasya.sayHi(); // Меня зовут: Вася

/*
vasya = {
   name: "Вася",
   sayHi: function() { ... }
}
*/

Function Constructor

  • Функции-конструкторы или просто конструкторы являются обычными функциями, именовать которые следует с заглавной буквы.
  • Конструкторы следует вызывать при помощи оператора new. Такой вызов создаёт пустой this в начале выполнения и возвращает заполненный в конце.

Мы можем использовать конструкторы для создания множества похожих объектов.

Task

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

JS

By Oleg Rovenskyi

JS

function constructor

  • 286