如何改变this的指向
这是我参与更文挑战的第3天,活动详情查看: 更文挑战
如何改变this的指向呢?ECMAScript规范里面给了我们两种方法,call与apply方法。但是这两种方法有什么区别呢?可以说call与apply在作用上一摸一样,只是有传参数的不同。
apply()
apply方法传入两个参数:第一个是函数上下文的对象,第二个是一个作为函数参数所组成的数组。
var obj = {
name : 'dddd'
}
function func(firstName, lastName){
console.log(firstName + ' ' + this.name + ' ' + lastName);
}
func.apply(obj, ['A', 'B']); // A dddd B
我们可以看到obj作为func的函数上下文的obj。func中的this指向obj。参数 A 和 B 是放在数组中传入 func 函数,分别对应 func 参数的列表元素。
call( )
call 方法第一个参数也是作为函数上下文的对象,但是后面传入的是一个参数列表,而不是单个数组。
var obj = {
name: 'dddd'
}
function func(firstName, lastName) {
console.log(firstName + ' ' + this.name + ' ' + lastName);
}
func.call(obj, 'C', 'D'); // C dddd D
对比 apply 我们可以看到区别,C 和 D 是作为单独的参数传给 func 函数,而不是放到数组中。
所以我们对于什么时候该用什么方法,其实不用纠结。如果你的参数本来就存在一个数组中,那自然就用 apply,如果参数比较散乱相互之间没什么关联,就用 call。
apply 和 call 的用法
1.改变 this 指向
var obj = {
name: 'dddd'
}
function func() {
console.log(this.name);
}
func.call(obj); // dddd
// 我们都知道call的第一个参数是函数上下文的对象,这里把obj传给func相当于函数里的 this //便指向了 obj 对象。
func(){
console.log(obj.name)
}
2.调用函数
apply、call 方法都会使函数立即执行,因此它们也可以用来调用函数。
function func() {
console.log('dddd');
}
func.call();//这里我们调用func.call()相当于直接执行func函数,会直接打印dddd
3.bind方法
if (!Function.prototype.bind) {
Function.prototype.bind = function () {
var self = this, // 保存原函数
context = [].shift.call(arguments), // 保存需要绑定的this上下文
args = [].slice.call(arguments); // 剩余的参数转为数组
return function () { // 返回一个新函数
self.apply(context,[].concat.call(args, [].slice.call(arguments)));
}
}
}
这里我们自己实现了bind的方法。留一个作业,随后一行的self.apply(context,[].concat.call(args, [].slice.call(arguments)));中apply的参数为何不是args而是要[].concat.call(args, [].slice.call(arguments))这样。可以把你的想法留在评论区。。。
从输出可以看出args是f.binding里除了第一个参数剩下所有的参数,而[].slice.call(arguments)是f.binding后第二个括号里的参数,args的this是Function.prototype.binding,[].slice.call(arguments)的this是f.binding(obj)()。\color{#FFFFFF}{从输出可以看出 args 是 f.binding 里除了第一个参数剩下所有的参数,而 [].slice.call(arguments) 是 f.binding 后第二个括号里的参数, args 的 this 是 Function.prototype.binding,[].slice.call(arguments) 的 this 是 f.binding(obj)()。}