手动实现call、apply和bind
如果没有传参,那么this默认指向的window
let a = { value: 1 } function parent(sex, weight) { this.name = '1' this.age = 12 this.sex = sex ? sex : null this.weight = weight ? weight : null console.log(123) }
call的实现 call接受参数的方式 call(obj, params1, params2, ....)
Function.prototype.myCall = function (context) { let currentObj = context ? context : window // 这里就是传入的第一个参数 currentObj.fn = this // 将parent函数存起来,parent调用的myCall,此时this指向的就是该方法 let arg = [...arguments].slice(1) // 将参数中除了第一个之后的全部存起来,第一个就是上下文要用的这个对象 console.log(...arg) currentObj.fn(...arg) // 将参数传入,此时调用fn的是currentObj 即为传入的对象a,所以parent中的this会指向a delete context.fn // 将函数删除 }
// 测试代码
// parent.myCall(a, 'mingzi', 'nianling')
// console.log(a);
apply的实现 apply接受参数的方式 call(obj, [params1, params2, ....])
Function.prototype.myApply = function (context) { let currentObj = context ? context : window // 这里就是传入的第一个参数 currentObj.fn = this // 将parent函数存起来,parent调用的myCall,此时this指向的就是该方法 console.log(arguments) // [{value: 1}, ['张三', '12']] if(arguments[1]) { currentObj.fn(...arguments[1]) } else { currentObj.fn() } delete currentObj.fn } // 测试代码 // parent.myApply(a, ['boy', '50']) // console.log(a)
bind()实现
// 实现bind()方法 调用bind()必须是一个函数 可以通过new修改this new的优先级最高 bind()可以将参数分两次传递进来 Function.prototype.myBind = function (context) { if(typeof this !== "function") { // 如果不是函数则直接抛出 throw new TypeError('Error') } let self = this // 保存this,即为parent let arg = [...arguments].slice(1) // 将参数中除了第一个之后的全部存起来 // bind()返回的是一个函数,所以可以使用new,并且会修改this的指向 return function F() { if(this instanceof F) { // 如果new执行此时即为true return new self(...arg, ...arguments) // 返回new parent(第一次传递的参数, 第二次传递的参数) =》 arguments是执行返回的函数时的参数 } return self.apply(context, [...arg, ...arguments]) // 如果没有执行new 那么直接执行parent,通过apply会将this执行最初传进来的对象a } } // 测试代码 let bindResult = parent.myBind(a, 'women') let result = new bindResult('666') console.log(result);