this

this对象是在运行时基于函数的执行环境绑定的(抛开箭头函数)
当函数被作为某个对象的方法调用时,this等于那个对象
this等于最后调用函数的对象

call()方法与apply()方法的作用相同,它们的区别仅在于接收参数的方式不同。
————————《JavaScript高级程序设计》

call

call()方法可以指定一个this的值(第一个参数),并且分别传入参数(第一个参数后面的就是需要传入函数的参数,需要一个一个传)call()改变this指向

  1. var first = '大黑刀·夜',
  2. second = '二代鬼彻',
  3. third = '初代鬼彻',
  4. fourth = '时雨';
  5. var zoro = {
  6. first: '和道一文字',
  7. second: '三代鬼彻',
  8. third: '雪走',
  9. fourth: '秋水'
  10. };
  11. function sayYourWeapon(num, num2) {
  12. console.log(`这是我${num}得到的刀"${this[num]}"`)
  13. console.log(`这是我${num2}得到的刀"${this[num2]}"`)
  14. }
  15. sayYourWeapon('first', 'third'); // 这是我first得到的刀"大黑刀·夜";这是我third得到的刀"初代鬼彻"
  16. sayYourWeapon.call(zoro, 'first', 'fourth'); // 这是我first得到的刀"和道一文字";这是我fourth得到的刀"秋水"

上面这段代码很明显的改变了this的指向,如果直接调用sayYourWeapon()必然输出的是全局全局变量first和third的值,而我后面通过sayYourWeapon.call(zoro, ‘first’, ‘fourth’)中的call()方法
因为改变了函数中的this值,就是传入的zoro,把this值从全局对象改成了zoro对象
所以后面输出的也都是对象zoro中的’first’, ‘fourth’的值

apply

apply()方法可以指定一个this的值(第一个参数),并且传入参数数组(参数需要在一个数组或者类数组中)

  1. var first = '大黑刀·夜',
  2. second = '二代鬼彻',
  3. third = '初代鬼彻',
  4. fourth = '时雨';
  5. var zoro = {
  6. first: '和道一文字',
  7. second: '三代鬼彻',
  8. third: '雪走',
  9. fourth: '秋水'
  10. };
  11. function sayYourWeapon(num, num2) {
  12. console.log(`这是我${num}得到的刀"${this[num]}"`)
  13. console.log(`这是我${num2}得到的刀"${this[num2]}"`)
  14. }
  15. sayYourWeapon('first', 'third'); // 这是我first得到的刀"大黑刀·夜";这是我third得到的刀"初代鬼彻"
  16. - sayYourWeapon.call(zoro, 'first', 'fourth'); // 这是我first得到的刀"和道一文字";这是我fourth得到的刀"秋水"
  17. + sayYourWeapon.apply(zoro, ['first', 'fourth']); // 这是我first得到的刀"和道一文字";这是我fourth得到的刀"秋水"

可以看到,我全篇就只是把call改成了apply,并且把之前'first', 'fourth'这么传进去的参数改成了['first', 'fourth']一个数组。如果我们是在一个函数当中使用,那我们还可以直接使用arguments这个类数组对象

  1. var first = '大黑刀·夜',
  2. second = '二代鬼彻',
  3. third = '初代鬼彻',
  4. fourth = '时雨';
  5. var zoro = {
  6. first: '和道一文字',
  7. second: '三代鬼彻',
  8. third: '雪走',
  9. fourth: '秋水'
  10. };
  11. function sayYourWeapon(num, num2) {
  12. console.log(`这是我${num}得到的刀"${this[num]}"`)
  13. console.log(`这是我${num2}得到的刀"${this[num2]}"`)
  14. }
  15. function mySayYourWeapon(num, num2) {
  16. sayYourWeapon.apply(zoro, arguments) // 我们自己声明一个函数,并且在里面调用apply,这是我们只需要传入arguments这个参数,而不需要想call那样一个一个传进去了
  17. }
  18. sayYourWeapon('first', 'fourth'); // 这是我first得到的刀"大黑刀·夜";这是我fourth得到的刀"时雨"
  19. mySayYourWeapon('first', 'fourth'); // 这是我first得到的刀"和道一文字";这是我fourth得到的刀"秋水"

bind

bind()方法不会立即执行目标函数,而是返回一个原函数的拷贝,并且拥有指定this值和初始函数
原函数拷贝

  1. function a() {}
  2. console.log(typeof a.bind() === 'function'); // 返回是true,先证明a.bind()是一个函数
  3. console.log(a.bind()); // 输出function a() {},跟原函数一样
  4. console.log(a.bind() == a); // false
  5. console.log(a.bind() === a); // false 不管是 === 还是 == 都是false,证明是拷贝出来一份而不是原先的那个函数

bind()方法在传参上跟call是一样的,第一个参数是需要绑定的对象,后面一次传入函数需要的参数,如下⬇️

  1. var name = 'Jack Sparrow';
  2. var onePiece = {
  3. name: 'Monkey·D·Luffy'
  4. };
  5. function sayWhoAmI() {
  6. console.log(this.name)
  7. }
  8. var mySayWhoAmI = sayWhoAmI.bind(onePiece)
  9. sayWhoAmI(); // Jack Sparrow
  10. mySayWhoAmI(); // Monkey·D·Luffy

一个简单的实现,本来输出的是全局变量’Jack Sparrow’,后来经过bind以后绑定上了对象onePiece,所以输出的就是对象onePiece中的nodeMonkey·D·Luffy。
那需要传参的时候怎么办

  1. var first = '大黑刀·夜',
  2. second = '二代鬼彻',
  3. third = '初代鬼彻',
  4. fourth = '时雨';
  5. var zoro = {
  6. first: '和道一文字',
  7. second: '三代鬼彻',
  8. third: '雪走',
  9. fourth: '秋水'
  10. };
  11. function sayYourWeapon(num, num2) {
  12. console.log(`这是我${num}得到的刀"${this[num]}"`)
  13. console.log(`这是我${num2}得到的刀"${this[num2]}"`)
  14. }
  15. // 既然我们知道bind是返回一个函数,那我们声明一个变量来接这个函数会看的直观一些
  16. var mySayYourWeapon = sayYourWeapon.bind(zoro, 'first', 'fourth'); // 传入初始参数
  17. var hisSayYourWeapon = sayYourWeapon.bind(zoro); // 只传入目标对象
  18. sayYourWeapon('first', 'third');
  19. mySayYourWeapon(); // 因为我们当时bind绑定函数的时候已经传入了目标对象zoro和指定的参数,所以这里就不需要传参数了
  20. hisSayYourWeapon( 'first', 'fourth'); // 当然我们开始bind绑定函数的时候不传入,在调用的时候再传入参数也是可以的

上面的代码我们可以发现mySayYourWeapon和hisSayYourWeapon在bind的时候一个传入了初始的参数,一个没有传入,但是后续调用的时候可以再传
既然是初始化参数,那我们就可以预设参数一个,然后再传一个——————偏函数(不知道自己理解的对不对,但是肯定是有这么个功能,不懂的可以移步MDN web docs的Function.prototype.bind中的偏函数

call、apply以及bind