Что касается вызова, применения и связывания в 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)
«Знак равенства» здесь на самом деле не является строгим, потому что разница между тремя ключевыми словами и принципом, стоящим за ним, не может быть суммирована только одним знаком равенства, но для понимания концепции и применения в реальных ситуациях это и т. д. формула не обязательно является хорошей идеей.