我们来看下面的一段代码
function Man (name) {
this.name = name
}
let man = new Man('tom')
var name = 'window'
// 问候一下
let say = function (call, word) {
console.log(`${call} ${this.name} ${word}`)
}
say('hello', 'welcome')
// hello window welcome上面的代码很好理解,say() 的调用方是 window,所以 this.name 也就等于 window 下的变量 name 了。那么如果我想对 man 进行问候呢?我们可能会有下面的想法
man.say = say
man.say('hello', 'welcome')
// hello tom welcome的确这样是可以达到目的的,但是 say 很可能就是一个公共方法,不属于任何其它对象,我只是想临时调用一下而已,修改原型链就显得有点不太合适了。那么又该怎么做呢?
其实说到底,我们最终要实现的目标是改变 say 方法调用的 this 指向,从 window 变成 man,这个时候就该请出我们今天的 3 个主角了:call() 、apply()、bind(),这三个方法实际上就是函数原型链 Function.prototype 上的方法,每个函数都拥有的,主要用来改变函数的 this 指向。
call
先上代码
function Man (name) {
this.name = name
}
let man = new Man('tom')
var name = 'window'
// 问候一下
let say = function (call, word) {
console.log(`${call} ${this.name} ${word}`)
}
say.call(man, 'hello', 'welcome')
// hello tom welcomecall 的语法是
fun.call(thisArg, arg1, arg2, ...)thisArg 表示 this 指向,如果为 null 和 undefined 则指向全局对象。后面的为参数列表。
apply
和 call 很类似,唯一不同的只是 apply 参数的传递不是一个一个,而是整个数组一次传入。
...
say.apply(man, ['hello', 'welcome'])
// hello tom welcome语法
func.apply(thisArg, [argsArray])注意这里的 argsArray 不光可以是数组,还可以是我们前面讲过的类数组对象
...
let param = {
length: 2,
0: 'hello',
1: 'welcome'
}
say.apply(man, param)
// hello tom welcome经常有同学记不清这俩之间的区别,我总结了一个记忆方法,call、call、call、call 有点类似射击,是一个一个,而 apply 相当于覆盖应用,一次性就传入了。
其实运用 ES6 展开符也可以很轻易地像 apply 一样使用 call
...
say.call(man, ...['hello', 'welcome'])
// hello tom welcomebind
和 call 语法类似
fun.bind(thisArg[, arg1[, arg2[, ...]]])但是作用却不一样
...
let greet = say.bind(man)
greet('hello', 'welcome')
// hello tom welcome可以看到,不像 call 和 apply,bind 并非是立即执行的,而是会新生成一个新的方法,之后可随意调用。当然也可以提前将参数 bind 进去
...
let greet = say.bind(man, 'hello', 'welcome')
greet()
// hello tom welcome或者
...
let greet = say.bind(man, 'hello')
greet('welcome')
// hello tom welcome这三个方法在实际开发中是经常会用到的,一定要搞清楚三者的用法和区别。
注:箭头函数不绑定
this,所以使用上面的三个方法是无法绑定 this 的。
最新评论