Понимание вызова, применения и привязки в JS из однострочного уравнения

JavaScript
Понимание вызова, применения и привязки в JS из однострочного уравнения

Что касается вызова, применения и связывания в JS, я считаю, что все, как и я, прочитали бесчисленное количество статей по теме и имеют собственное понимание. Так что эта статья не научно-популярная, а просто запись моего собственного понимания.

Моя учебная привычка состоит в том, чтобы соединять различные, казалось бы, изолированные точки знаний, всесторонне понимать и применять их, а также понимать их через самые простые и интуитивно понятные идеи. Таким образом, эта статья соединит относительно сложную точку знаний в JS, позвоните, примените и свяжите через очень краткое уравнение:

cat.call(dog, a, b) = cat.apply(dog, [a, b]) = (cat.bind(dog, a, b))() = dog.cat(a, b)

Чтобы понять эти три ключевых слова в JS, вы должны сначала понять, для чего они используются. Чтобы было сложнее, вы можете процитировать исходный текст документа MDN:

Объект в call() может вызывать функцию, принадлежащую текущему объекту. Вы можете использовать call() для достижения наследования: написать метод и позволить другому новому объекту наследовать его (вместо повторного написания метода в новом объекте).

Проще говоря, можно процитировать фразу, которую все видели:

Для динамического изменения контекста, в котором выполняется функция.

Или это

Чтобы изменить указатель this внутри тела функции

Приведенные выше объяснения все верны, и в этом нет никакой проблемы, но они вводятся继承,上下文,thisэти дополнительные очки знаний. Если я просто хочу использовать наиболее интуитивный способ понять роль этих трех ключевых слов, возможно, я смогу понять это так:

Определите объект кошки:

class Cat {
  constructor (name) {
    this.name = name
  }

  catchMouse(name1, name2) {
    console.log(`${this.name} caught 2 mouse! They call ${name1} and ${name2}.`)
  }
}

Этот кошачий объект умеет ловить мышейcatchMouse().

Затем аналогичным образом определите объект собаки:

class Dog {
  constructor (name) {
    this.name = name
  }

  biteCriminals(name1, name2) {
    console.log(`${this.name} bite 2 criminals! Their name is ${name1} and ${name2}.`)
  }
}

Этот собачий предмет способен кусать плохих людейbiteCriminal().

Затем мы создаем экземпляры двух объектов, чтобы получить кошку по имени «Китти» и собаку по имени «Собачка»:

const kitty = new Cat('Kitty')
const doggy = new Dog('Doggy')

Сначала позвольте им сыграть свои навыки друг против друга:

kitty.catchMouse('Mickey', 'Minnie')
// Kitty caught mouse! They call Mickey and Minnie.

doggy.biteCriminal('Tom', 'Jerry')
// Doggy bite a criminal! Their name is Tom and Jerry.

Теперь мы хотим дать Песику возможность ловить мышей. Что нам делать, не используя эти три ключевых слова?

Схема A: Измените объект «Собака» и непосредственно определите навык ловли мыши, такой же, как у «Кошки».

Вариант Б: позволить Песику съесть Китти и напрямую переварить и поглотить все способности Китти.

На самом деле решения решения A и решения B похожи, и объект Dog нужно модифицировать, но решение B будет проще и грубее:

class Dog {
  constructor (name, kitty) {
    this.name = name
    this.catchMouse = kitty.catchMouse
  }

  biteCriminals(name1, name2) {
    console.log(`${this.name} bite 2 criminals! Their name is ${name1} and ${name2}.`)
  }
}

const kitty = new Cat('Kitty')
const doggy = new Dog('Doggy', kitty)

doggy.catchMouse('Mickey', 'Minnie')
// Doggy caught 2 mouse! They call Mickey and Minnie.

Приведенный выше метод слишком неэлегантен, и часто при определении объекта Dog нет намерения добавлять к нему метод отлова мыши. Итак, есть ли способ разрешить экземплярам Doggy ловить мышей без изменения содержимого объекта Dog? Ответ заключается в использовании вызова, применения или связывания ключевых слов:

kitty.catchMouse.call(doggy, 'Mickey', 'Minnie')

kitty.catchMouse.apply(doggy, ['Mickey', 'Minnie'])

const doggyCatchMouse = kitty.catchMouse.bind(doggy, 'Mickey', 'Minnie')
doggyCatchMouse()

// Doggy caught 2 mouse! They call Mickey and Minnie.
// Doggy caught 2 mouse! They call Mickey and Minnie.
// Doggy caught 2 mouse! They call Mickey and Minnie.

И наоборот, таким же образом можно дать Китти возможность кусать плохих парней, и читатели могут попробовать это сами.

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

Вернемся к уравнению в начале статьи:

cat.call(dog, a, b) = cat.apply(dog, [a, b]) = (cat.bind(dog, a, b))() = dog.cat(a, b)

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