从一行等式明白JS当中的call, apply和bind

关于JS当中的call,apply和bind,置信人人和我一样,已看过了无数篇相干的文章,都有本身的邃晓。所以这篇文章并不是什么科普类的文章,仅仅是把我本身的邃晓记录下来。

我的进修习气,是喜好把种种看似伶仃的知识点串连起来,综合邃晓并应用,经由过程最简朴最直观的思绪把它邃晓透。所以,这篇文章将经由过程一段异常简约的等式,把JS当中一个相对较难的知识点,call,apply和bind给串连起来:

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

要邃晓JS当中的这三个关键字,首先得弄清楚它们是用来干吗的。庞杂些来讲,可以援用MDN文档的原文:

可以让call()中的对象挪用当前对象所具有的function。你可以运用call()来完成继续:写一个要领,然后让别的一个新的对象来继续它(而不是在新对象中再写一次这个要领)。

简朴些来讲,可以援用人人都看过的一句话:

为了动态转变某个函数运行时的上下文(context)。

又或许是

为了转变函数体内部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()

接下来,我们实例化两个对象,离别获得一只叫“Kitty”的猫和叫“Doggy”的狗:

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.

如今,我们愿望给予Doggy抓老鼠的才能,假如不运用这三个关键字,应当怎么做呢?

计划A:修正Dog对象,直接为其定义一个和Cat雷同的抓老鼠妙技。

计划B:让Doggy吃掉Kitty,直接消化吸收Kitty的一切才能。

实在计划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对像的时刻根本就没有打算过要为它增加抓老鼠的要领。那末有无一种方法可以在不修正Dog对象内容的前提下,让Doggy实例也可以具有抓老鼠的方法呢?答案就是运用call,apply或许bind关键字:

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.

反过来,让Kitty具有咬暴徒的才能,也可以经由过程这类方法完成,读者可以自行尝试。

看到这里,置信读者已可以邃晓call,apply和bind的区分及作用,反过来再检察各自的观点,应当也可以更轻易邃晓。

回到文章开首的等式:

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

这里的“等号”实在并不严谨,由于三个关键字的区分及背地的道理一定不是戋戋一个等号就可以归纳综合的,然则关于观点的邃晓以及现实情况下的应用来讲,这条等式未必不是一个好的思绪。

    原文作者:jrainlau
    原文地址: https://segmentfault.com/a/1190000014182270
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞