apply、call、bind的学习总结

call

先来一个例子

const obj = {
  name: 'xiaoming',
  log: function(a) {
    console.log(this.name, a);
  }
}
obj.log(); // xiaoming undefined
复制代码

call方法调用一个函数, 其具有一个指定的this值和分别地提供的参数

const callObj = {
  name: 'call',
}
obj.log.call(callObj, 'callObj'); // call callObj
复制代码

在非严格模式下,如果则指定为nullundefinedthis值会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象

window.name = 'window';
obj.log.call(null, 'windowObj'); // window windowObj


// call方法的实现
Function.prototype.call = function(context) {
  if (typeof this !== 'function') {
    throw new TypeError('error');
  }
  context = context || window;
  context.fn = this;
  const result = context.fn(...[...arguments].slice(1));
  delete context.fn;
  return result;
}
复制代码

apply

apply方法的作用和call方法类似,区别就是call方法接受的是参数列表,而apply方法接受的是一个参数数组。

const applyObj = {
  name: 'apply',
}
obj.log.apply(applyObj, ['applyObj']); // apply applyObj
/*在非严格模式下,如果则指定为null和undefined的this值会自动指向全局对象(浏览器中就是window对象)
同时值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象*/
window.name = 'window';
obj.log.apply(null, ['applyObj']); // window windowObj


// apply的实现
Function.prototype.apply = function(context) {
  if (typeof this !== 'function') {
    throw new TypeError('error');
  }
  context = context || window;
  context.fn = this;
  const result = arguments[1] ? context.fn(...arguments[1]) : context.fn();
  delete context.fn;
  return result;
};
复制代码

bind

const bindObj = {
  name: 'bind'
}
obj.log.bind(bindObj);
/* 这里并不会打印bind,而是返回一个函数
ƒ () {
  console.log(this.name);
}
由此可见,bind()方法创建一个新的函数 */
// 接着执行
obj.log.bind(bindObj)(); // 打印 bind
// 因此,当这个新函数被调用时其this置为提供的值
复制代码

bind的另一个最简单的用法是使一个函数拥有预设的初始参数。这些参数(如果有的话)作为bind的第二个参数跟在this(或其他对象)后面,之后它们会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们的后面。

function list() {
  return Array.prototype.slice.call(arguments);
}

console.log(list(1,2,3)); // [1, 2, 3]

const presetList = list.bind(null, 0);

console.log(presetList()); // [0]
console.log(presetList(1, 2, 3)); // [0, 1, 2, 3, 4]
复制代码

绑定函数适用于用new操作符去构造一个由目标函数创建的新的实例。当一个绑定函数是用来构建一个值的,原来提供的 this 就会被忽略。然而, 原先提供的那些参数仍然会被前置到构造函数调用的前面。

function Point(a, b) {
  this.a = a;
  this.b = b;
}
Point.prototype.toString = function() {
  console.log(this.a + this.b);
}
const p1 = new Point(1,2);
p1.toString(); // 3

const obj = {}
var P2 = Point.bind(obj, 1);
const p3 = new P2(2);
console.log(p3.toString()); // undefined
console.log(p3 instanceof P2); // true
console.log(p3 instanceof Point); // true
new Point(1, 2) instanceof P2; // true
复制代码

bind的实现

Function.prototype.bind = function(context) {
  if (typeof this !== 'function') {
    throw new Error('Function.prototype.bind - what is trying to be bound is not callable');
  }
  const slice = Array.prototype.slice;
  const args = slice.call(arguments, 1);
  const self = this;
  const F = function(){};
  const fbound = function() {
    return self.apply(this instanceof F ? this: context, args.concat(slice.call(arguments)));
  }
  if (this.prototype) {
    F.prototype = this.prototype;
  }
  fbound.prototype = new F();
  return fbound;
}
复制代码

结语

本人能力有限,难免出现错误内容,欢迎大佬们看到后,指出文章的错误以及给出更优质的答案

参考链接

MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/call

转载于:https://juejin.im/post/5bc590b06fb9a05d07196cc2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值