一般函数中this的指向

1,281 阅读4分钟

引言:this是在面试和工作中经常会遇到的东西,也是必须要掌握的内容

一、this的指向

一般情况下,谁调用,this就指向谁

下面来看几个例子

var a = 1;
function fn() {
    console.log(this.a);
}
fn(); // 输出1

在这里this指向的就是Window,验证打印一下this看看

function fn() {
    console.log(this);
}
fn(); // 输出Window
console.log(this); // 输出Window

这是普通函数中调用和在外部调用this的情况,现在再来看一个例子

var a = 1;
var obj = {
    a: 2,
    fn: function() {
        console.log(this.a);
    }
}
obj.fn(); // 输出2

这里可以发现this指向的就不再是Window,而是obj。发现没有这个例子中是用obj调用的fn,所以fn中的this就指向obj

上个例子中在外部直接调用fnthis指向的就是外部的环境Window

所以可以得出结论,谁调用,this就指向谁。

二、修改this的指向

可以通过callapplybind来修改this的指向

看一个例子

example: 希望输出weaponname

var garen = {
    name: "盖伦",
    age: 22,
    say: function () {
        console.log("我的武器是" + this.name);
    },
};

var weapon = {
    name: "暴风大剑",
};

garen.say(); // 输出:我的武器是盖伦

遇到这种情况时,就需要修改this的指向

这里有几种方法可以修改

1. call

call方法可以接收多个参数

call(修改后的this指向, 参数1, 参数2, 参数3...)

修改后的example

var garen = {
    name: "盖伦",
    age: 22,
    say: function () {
        console.log("我的武器是" + this.name);
    },
};

var weapon = {
    name: "暴风大剑",
};

garen.say.call(weapon) // 输出:我的武器是暴风大剑

call()传入多个参数的使用

var garen = {
    name: "盖伦",
    age: 22,
    say: function (desc) {
        console.log("我的武器是" + this.name, desc);
    },
};

var weapon = {
    name: "暴风大剑",
};

garen.say.call(weapon, "我没有特色", "我很肉") // 输出:我的武器是暴风大剑 我没有特色

这里可以看到输出的内容少了第三个参数,那是因为desc只传递了第二个参数,第三个参数没有传递。那传递多个参数可以通过新增参数的方式,或者使用 ES6 的扩展运算符来完成。

最终代码

var garen = {
    name: "盖伦",
    age: 22,
    say: function (...desc) {
        console.log("我的武器是" + this.name, ...desc);
    },
};

var weapon = {
    name: "暴风大剑",
};

garen.say.call(weapon, "我没有特色", "我很肉") // 输出:我的武器是暴风大剑 我没有特色 我很肉

2. apply

applycall的区别就在于接收的参数,call能接收多个参数,但apply只能接收2个参数。

第一个和call一样,都是this的指向。

第二个参数是一个数组,将call中的剩余参数都放到了这个数组中。

apply(修改后的this指向, [参数1, 参数2, 参数3...])

仅此而已,其他用法完全一样,只是接收参数的方式改变了。

那 example 用apply的写法

var garen = {
    name: "盖伦",
    age: 22,
    say: function (...desc) {
        console.log("我的武器是" + this.name, ...desc);
    },
};

var weapon = {
    name: "暴风大剑",
};

// 只有这里修改了
garen.say.apply(weapon, ["我没有特色", "我很肉"]) // 输出:我的武器是暴风大剑 我没有特色 我很肉

3. bind

bindcall也很相似,不过返回结果不同,bind是返回一个新函数,callapply不会返回新函数,而是直接执行原函数,并返回函数执行的结果

bind(修改后的this指向, 参数1, 参数2, 参数3...)()

那 example 用apply的写法

var garen = {
    name: "盖伦",
    age: 22,
    say: function (...desc) {
        console.log("我的武器是" + this.name, ...desc);
    },
};

var weapon = {
    name: "暴风大剑",
};

// 只有这里修改了
garen.say.bind(weapon, "我没有特色", "我很肉")() // 输出:我的武器是暴风大剑 我没有特色 我很肉

三、总结

一般情况下this指向调用它的实例,但也可以手动修改this的指向,callapplybind都是用来修改this的指向的,区别在于:

  1. call接收多个参数,执行原函数,返回结果
  2. apply接收两个参数,第二个参数是数组,执行原函数,返回结果
  3. bind接收多个参数,不会执行函数,只会返回新函数,所以使用时要再调用一次
call(this,param1,param2,param3...)
apply(this,[param1,param2,param3...])
bind(this,param1,param2,param3...)()

特别注意:this参数为null的情况

callapplybind的第一个this参数可以为null

如果是nullundefined的话,修改后的指向会变成window

call、apply、bind实现原理

在了解了用法后可以对其实现原理进行了解,点击跳转 手写call、apply、bind思路及实现