call()
、apply()
、bind()
方法的做用都是改变函数运行时this的指向。 bind()
是返回对应的函数,便于稍后调用;call()
和apply()
则是当即调用。数组
相同点app
两者做用彻底相同,只是接收参数上的不一样。若是不传入第一个参数,则默认上下文是 window
。函数
call
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 // 返回函数执行结果 }
示例this
let test = { name: "test" } let fun = { fn: function () { console.log(this.name) } } fun.fn.myCall(test) // test
apply
注意: 上述指定的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 }
示例prototype
function fn() { console.log(this.age) } let person = { age: 12 } fn.myApply(person) // 12
bind
方法会建立一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以建立它时传入bind()
的第一个参数做为this
,传入bind
方法的 其余参数以及和绑定函数运行时自己的参数 ,将按照顺序做为原函数的参数来调用原函数。code
new
操做符调用绑定函数时,该参数无效。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 undefined f.myBind(obj, 'b', 'c')('e') // a b c e f.myBind(obj, 'b', 'c', 'd')('e') //a b c d