手写实现call、apple、bind 方法
认识call、apple、bind 三者
- 功能:用来改变 this 的指向
- call() 与 apple() 类似,不同的是call包含多个参数: call(thisObj, 1 , 2, 3 …);而apple的参数是一个数组:apple(thisObj, [1, 2, 3 …])。
- call、apple、bind的区别:call、apple 是调用后立即返回结果;bind是返回一个函数
myCall() 方法的实现
看下面一段原生call方法
var obj1 = {
name: '假装文艺浪',
hobby: '打篮球',
fn: function () {
console.log('爱好', this.hobby)
}
}
let obj = {
hobby: '敲代码'
}
obj1.fn()
obj1.fn.call(obj)
// 爱好 打篮球
// 爱好 敲代码
当我们使用call方法时,打印的是 “敲代码” 而不是 “打篮球”,this指向了 obj 对象中的 hobby,即改变了this的指向
接下来实现我们自己的call()方法
Function.prototype.myCall = function(context = window, ...args) {
if (typeof this !== 'function') {
throw new TypeError('Type Error')
}
// Symbol 独一无二 ES6
const fn = Symbol('fn')
context[fn] = this
const res = context[fn](...args)
delete context[fn]
return res
}
obj1.fn()
obj1.fn.myCall(obj)
// 爱好 打篮球
// 爱好 敲代码
查看打印结果,与原生call方法无异
apple()方法的实现
原生的apple
var obj1 = {
name: '假装文艺浪',
hobby: '打篮球',
fn: function (x, y) {
console.log('爱好',this.hobby)
console.log(x + y)
}
}
let obj = {
hobby: '敲代码'
}
obj1.fn(2,3)
obj1.fn.apply(obj,[1,2])
// 爱好 打篮球
// 5
// 爱好 敲代码
// 3
call与apple的不同就是参数的形式,我们的apple() 方法的实现
Function.prototype.myApple = function(context = window, args) {
if (typeof this !== 'function') {
throw new TypeError('Type Error')
}
const fn = Symbol('fn')
context[fn] = this
const res = context[fn](...args)
delete context[fn]
return res
}
obj1.fn(2,3)
obj1.fn.myApple(obj,[1,2])
// 爱好 打篮球
// 5
// 爱好 敲代码
// 3
bind()方法的实现
原生的bind()方法
function fn (x,y) {
console.log(this.hobby)
console.log(x + y)
}
let obj = {
hobby: '敲代码'
}
fn(2,3)
console.log(typeof fn.bind(obj,1,2))
fn.bind(obj,1,2)()
// undefined
// 5
// function
// 敲代码
// 3
通过打印的结果可以看出,bind()方法返回的是一个函数,而不是执行结果
this指向了obj对象
下面实现我们的bind()方法,
Function.prototype.myBind = function(context, ...args) {
// 判断是否为函数
if (typeof this !== 'function') {
throw new Error("Type Error");
}
// 保存this的值,指向函数
var self = this;
return function F() {
// 考虑new的情况
if(this instanceof F) {
return new self(...args, ...arguments)
}
// 调用apply,改变this执行
return self.apply(context, [...args, ...arguments])
}
}
fn(2,3)
console.log(typeof fn.myBind(obj,1,2))
fn.myBind(obj,1,2)()
// undefined
// 5
// function
// 敲代码