本文github地址,欢送star

apply、call、bind区别

这三个办法都是挂载 Funtion 原型上的办法,所以调用者必须是个函数。

  • Function.prototype.call()
  • Function.prototype.apply()
  • Function.prototype.bind()

这三个函数的应用语法:

func.call(thisArg, param1, param2, ...)func.apply(thisArg, [param1, param2, ...])func.bind(thisArg, param1, param2, ...)

他们共有的作用都能够扭转函数运行时 this 的指向。

callapply 的区别在于传递参数的形式不同:

  • apply 的第 2 个参数为数组
  • call 则是从第 2 个至第 N 个都是给 func 的传参

bindcallapply 的区别在于函数是否立刻执行:

  • callapply是在扭转了函数的 this 指向之后立马执行
  • bind 会返回一个函数,尽管扭转了 functhis 指向,但不是马上执行, 而是调用返回的函数才执行

apply、call、bind 应用场景

获取数组的最值

能够通过 apply 来获取 Math.max() 最大值和 Math.min() 最小值。当然也能够开展来获取数组的最值。

let arr = [1, 2, 3];const max = Math.max.apply(null, arr); // es6 Math.max(...arr)const min = Math.min.apply(null, arr); // es6 Math.min(...arr)console.log(max); // 3console.log(min); // 1

判断数据类型

能够通过 Object.toString.call 来判断所有的数据类型。

// 判断原生对象const isPlainObject = val => Object.toString.call(val) === '[object Object]'// 判断字符串const isString = val => Object.toString.call(val) === '[object String]'

将类数组转为数组

类数组因为不是真正的数组,所有没有数组类型上自带的种种办法,所以要转为数组,能力调用数组的办法.

let arrayLike = {    '0': 'a',    '1': 'b',    '2': 'c',    length: 3};// ES5的写法let arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']// ES6的写法let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']

继承

组合继承应用call来实现。

function Parent() {    this.name = '张三';    this.age = 18;}Parent3.prototype.getName = function() {    return this.name;}function Child() {    Parent3.call(this);    this.address = 'beijing';}Child.prototype = new Parent3();Child.prototype.constructor = Child3;var s = new Child();console.log(s.getName()); // '张三'

手写实现

call的实现

Function.prototype.call = function (context, ...args) {  var context = context || window;  context.fn = this;  var result = eval('context.fn(...args)');  delete context.fn  return result;}

apply的实现

apply 和 call 基本原理是差不多的,只是参数存在区。

Function.prototype.apply = function (context, args) {  let context = context || window;  context.fn = this;  let result = eval('context.fn(...args)');  delete context.fn  return result;}c

bind的实现

bind 的实现思路根本和 apply 一样,然而在最初实现返回后果这里,bindapply 有着比拟大的差别,bind 不须要间接执行,须要通过返回一个函数的形式将后果返回,之后再通过执行这个后果,失去想要的执行成果。

Function.prototype.bind = function (context, ...args) {    if (typeof this !== "function") {      throw new Error("this must be a function");    }    var self = this;    var fbound = function () {        self.apply(this instanceof self ? this : context, args.concat(Array.prototype.slice.call(arguments)));    }    if(this.prototype) {      fbound.prototype = Object.create(this.prototype);    }    return fbound;}
  • bind须要返回一个函数,然而不能失落函数原型上的属性,因而fbound.prototype = Object.create(this.prototype);
  • this instanceof self当这个绑定函数被当做一般函数调用的时候,能够间接用context; 而返回的这个之后当做构造函数应用的时候,却是指向这个实例,所以this instanceof selftrue时,要用this。 因而这里加了这个判断。

总结

通过上述的剖析,咱们来总结下这三个函数的相同点和不同点,来帮忙更好的了解。

办法callapplybind
函数参数一个参数列表一个蕴含多个参数的数组多个参数
函数作用扭转函数运行时 this 指向扭转函数运行时 this 指向扭转函数运行时 this 指向
返回后果间接执行间接执行期待执行函数
底层实现通过eval通过eval调用apply