call()
、apply()
、bind()
办法的作用都是扭转函数运行时this的指向。 bind()
是返回对应的函数,便于稍后调用;call()
和apply()
则是立刻调用。
相同点
- 都是用来扭转函数执行时this的指向,即函数运行时的上下文;
- 第一个参数都是this要指向的对象;
- 都能够利用后续参数传参。
1、apply、call
二者作用完全相同,只是接管参数上的不同。如果不传入第一个参数,则默认上下文是 window
。
1)call
语法
- fun.call(context, arg1,arg2...)
- context: 在fun函数中运行时指定的this值
- arg1,arg2:指定的参数列表
实现原理
Function.prototype.myCall = function(context, ...args) { if( typeof this !== 'function') { throw new TypeError('Error') // 判断是否是函数调用 } context = context ? Object(context) : window // 原始值的this会指向该原始值的实例对象 因而须要Object转换成对象类型 context.fn = this // 函数的this指向隐式绑定到context上 const result = context.fn(...args) // 通过隐式绑定函数并传递参数 delete context.fn // 删除上下文对象的属性 return result // 返回函数执行后果}
示例
let test = { name: "test"}let fun = { fn: function () { console.log(this.name) }}fun.fn.myCall(test) // test
2)apply
语法
- fun.apply(context, [argsArr])
- context:在fun 函数运行时指定的this值
- argsArr:一个数组或者是类数组对象,其中数组中元素会作为独自参数传给fun。当参数值为null 或者undefined时,示意不须要传入任何参数。
留神: 上述指定的this值(thisArg)并不一定是该函数执行时真正的this值,如果该函数处于非严格模式下,则指定为null或者undefined时会主动指向全局对象(浏览中就是window对象),同时值为原始值(number、string、boolean)的this会指向该原始值的主动包装对象。
实现原理
Function.prototype.myApply = function(context) { if( typeof this !== 'function' ) { throw new TypeError('Error') } context = context ? Object(context) : window context.fn = this let result if(arguments[1]) { // 解决参数上和call有区别 result = context.fn(...arguments[1]) } else { result = context.fn() } delete context.fn return result}
示例
function fn() { console.log(this.age)}let person = { age: 12}fn.myApply(person) // 12
2、bind
bind
办法会创立一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创立它时传入bind()
的第一个参数作为this
,传入bind
办法的 其余参数以及和绑定函数运行时自身的参数 ,将依照程序作为原函数的参数来调用原函数。
语法
- fun.bind(context, arg1, arg2, ...)
- context:当绑定函数被调用时,该参数会作为原函数运行时的this指向;当应用
new
操作符调用绑定函数时,该参数有效。 - arg1,arg2...:绑定函数被调用时,这些参数将位于实参之前传递给绑定的办法。
实现原理
Function.prototype.myBind = function(context) { if( typeof this !== 'function' ) { throw new TypeError('Error') } let args = [...arguments].slice(1) // bind 函数中的参数 let self = this // 保留原函数 return function() { return self.apply(context, args.concat(...arguments)) // arguments 是内部函数传入的 }}
示例
let obj = { a: 'a'};function f(b, c, d) { console.log(this.a, b, c, d)}f.myBind(obj, 'b')('e') // a b e undefinedf.myBind(obj, 'b', 'c')('e') // a b c ef.myBind(obj, 'b', 'c', 'd')('e') //a b c d