call, apply, bind都是改变函数执行的上下文,说的直白点就是改变了函数this的指向。不一样的是:call和apply改变了函数的this,而且执行了该函数,而bind是改变了函数的this,并返回一个函数,但不执行该函数。数组
看下面的例子1:app
var doThu = function(a, b) { console.log(this) console.log(this.name) console.log([a, b]) } var stu = { name: 'xiaoming', doThu: doThu, } stu.doThu(1, 2) // stu对象 xiaoming [1, 2] doThu.call(stu, 1, 2) // stu对象 xiaoming [1, 2]
因而可知,在stu上添加一个属性doThu,再执行这个函数,就将doThu的this指向了stu。而call的做用就与此至关,只不过call为stu添加了doThu方法后,执行了doThu,而后再将doThu这个方法从stu中删除。函数
下面来看call函数的内部实现原理:this
Function.prototype.call = function(thisArg, args) { // this指向调用call的对象 if (typeof this !== 'function') { // 调用call的若不是函数则报错 throw new TypeError('Error') } thisArg = thisArg || window thisArg.fn = this // 将调用call函数的对象添加到thisArg的属性中 const result = thisArg.fn(...[...arguments].slice(1)) // 执行该属性 delete thisArg.fn // 删除该属性 return result }
apply的实现原理和call同样,只不过是传入的参数不一样而已。下面只给出代码,不作解释:prototype
Function.prototype.apply = function(thisArg, args) { if (typeof this !== 'function') { throw new TypeError('Error') } thisArg = thisArg || window thisArg.fn = this let result if(args) { result = thisArg.fn(...args) } else { result = thisArg.fn() } delete thisArg.fn return result }
bind的实现原理比call和apply要复杂一些,bind中须要考虑一些复杂的边界条件。bind后的函数会返回一个函数,而这个函数也可能被用来实例化:code
Function.prototype.bind = function(thisArg) { if(typeof this !== 'function'){ throw new TypeError(this + 'must be a function'); } // 存储函数自己 const _this = this; // 去除thisArg的其余参数 转成数组 const args = [...arguments].slice(1) // 返回一个函数 const bound = function() { // 可能返回了一个构造函数,咱们能够 new F(),因此须要判断 if (this instanceof bound) { return new _this(...args, ...arguments) } // apply修改this指向,把两个函数的参数合并传给thisArg函数,并执行thisArg函数,返回执行结果 return _this.apply(thisArg, args.concat(...arguments)) } return bound }