详解JS函数里的this关键字

246 阅读3分钟

1. this 关键字

在JS里面,每一个函数内部都有一个关键字 this,语法就是它本身,我们可以直接使用它。

但是:函数内部的this只和函数的调用方式有关,和函数的定义方式没有关系。 并且在函数内部this指向谁,完全取决于函数的调用方式。

  1. 全局定义的函数直接调用
function foo() {
    console.log(this);
}
// 此时this就指向了Window
foo();
  1. 对象内部的方式调用,此时谁调用函数,this就指向谁
let obj = {
  foo: function () {
    console.log(this);
  }
}
// 此时this指向obj
obj.fn();
  1. 定时器的处理函数
setTimeout(function () {
  console.log(this)
}, 1000)
// 此时定时器处理函数里面的 this 指向 windo
  1. 事件处理函数
div.onclick = function () {
  console.log(this)
}
// 当你点击 div 的时候,this 指向 div,也就是说this指向了事件源
  1. 自调用函数
(function () {
  console.log(this)
})()
// 此时 this 指向 window

我们再来看另外一种情况,虽然Car是首字母大写的函数,看起来像构造函数,但是因为在调用的时候,没有使用new关键字;所以就没有人帮你做4件事情:

  1. 创建 {}
  2. this => {}
  3. {key : value}
  4. return {key : value}

所以就当成普通函数来调用,普通函数默认返回undefined

由于普通函数是由window隐式帮我们调用,所以普通函数中的this指向window对象

<script>
function Car(color, brand){
            this.color = color;
            this.brand = brand;
        };

        var c1 = new Car('蓝色', 'benz');
        console.log(c1);// undefined

  
        function Car(color, brand){
            // 1. 创建一个空对象
            var me = {};
            // 2. 将me作为this来使用,添加属性和方法
            me.color = color;
            me.brand = brand;
            // 3. 将完成了属性挂载的对象返回出去
            return me;
        }

        var c1 = Car('蓝色','benz');
        console.log(c1);

        var c2 = Car('red', 'BMW')
        console.log(c2)
</script>

哪除了函数的基本调用的this指向之外,能不能改变this指向的方法呢?答案是可以的

2. this对象的转换

2.1 call

call方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向。

语法

函数名.call(要改变的this指向,要给函数传递的参数1,要给函数传递的参数2,.......);

var obj = { name: 'tom' }
function fn(a, b) {
  console.log(this);
  console.log(a);
  console.log(b);
}
fn(1, 2);
fn.call(obj, 1, 2);

以这段代码为例,函数的调用fn()的时候,函数内部的this指向Window

而在fn.call(obj,1,2);时,函数内部的this就指向了obj这个对象。

使用call方法的步骤:

  1. 会立即执行函数
  2. 第一个参数是你要改变的函数内部的this指向
  3. 第二个参数开始,依次向函数传递参数
2.2 apply

apply方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向。

语法

函数名.apply(要改变的 this 指向,[要给函数传递的参数1, 要给函数传递的参数2, ...]);

var obj = { name: 'tom' }
function fn(a, b) {
  console.log(this);
  console.log(a);
  console.log(b);
}
fn(1, 2);
fn.call(obj, [1, 2]);

函数在fn()的时候,函数内部的 this 指向 window

fn.apply(obj, [1, 2]) 的时候,函数内部的 this 就指向了 obj 这个对象。

使用 apply 方法的步骤:

  1. 会立即执行函数
  2. 第一个参数是你要改变的函数内部的 this 指向
  3. 第二个参数是一个 数组,数组里面的每一项依次是向函数传递的参数
2.3 bind

bind 方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向。

call / apply 有一些不一样,就是不会立即执行函数,而是返回一个已经改变了 this 指向的函数。

语法

var newFn = 函数名.bind(要改变的 this 指向); newFn(传递参数)

var obj = { name: 'tom' }
function fn(a, b) {
  console.log(this);
  console.log(a);
  console.log(b);
}
fn(1, 2);
var newFn = fn.bind(obj);
newFn(1, 2);

bind在调用的时候,不会执行 fn 这个函数,而是返回一个新的函数。

这个新的函数就是一个改变了 this 指向以后的 fn 函数。

fn(1, 2)的时候 this 指向 window

newFn(1, 2)的时候执行的是一个和 fn 一摸一样的函数,只不过里面的 this 指向改成了 obj