JavaScript之this指向

51 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情

前言

this 指向是一个非常重要的知识点,可以用在构造函数,表示实例对象;也可以用在其他场合。

this 总是返回一个对象

this 指向

之前的文章执行上下文中介绍过:在创建执行上下文(即调用函数)这个阶段,除了会确定变量对象(VO)、作用域以外,还会确定 this 指向,也就是说函数体内的this 指向跟函数在哪定义无关,跟如何调用函数有关

this 的指向规律可以总结为下面几点:

直接调用函数,在严格模式下,函数内的 this 会指向 undefined,在非严格模式下则会绑定到全局对象上(window或者global,取决于代码运行环境

function f1() {
    console.log(this); // 全局对象 window/global
}

function f2() {
    'use strict' // 开启严格模式
    console.log(this); // undefined
}

f1();
f2();

通过对象调用,this 指向调用的对象

const foo = {
    bar: 10,
    fn: function() {
        console.log(this);
        console.log(this.bar);
    }
}

// 通过 obj.function 的方式调用,this 会指向 obj
// 此处 this 指向 foo 对象,输出结果为:{ bar: 10, fn: function(){} }, 10
foo.fn(); 

let fn1 = foo.fn;
// 直接调用。上面赋值语句是将foo.fn的引用赋值给fn1
// 此处 this 指向全局对象 输出结果为:window/global undefined
fn1();

通过 new 关键字调用构造函数时,this 指向新创建的实例对象

function Person(name) {
    this.name = name;
}
Person.prototype.say = function() {
    console.log(this);
    console.log('hello ' + this.name);
}

const p = new Person('world');
// this 指向 实例对象 p
p.say(); // Person {name: 'world'} hello world

this 指向绑定事件的元素

DOM 元素绑定事件时,事件处理函数里面的 this 指向绑定了事件的元素。

target 属性有所区别,target 指向的是触发事件的元素。

<ul id="color-list-wrap">
  <li>red</li>
  <li>yellow</li>
  <li>blue</li>
  <li>green</li>
  <li>black</li>
  <li>white</li>
</ul>
let colorList = document.getElementById("color-list");
colorList.addEventListener("click", function (event) {
  console.log('this:', this); // 指向 ul 元素
  // 事件函数内部定义 callback 函数
  const callback = function() {
      // 直接调用函数, this 指向 全局对象 window
    console.log(this); // window
  }
  callback();
})

箭头函数this 默认使用的是外层函数的 this

const foo = {
    bar: 10,
    fn1: function() {
        console.log(this);
        console.log(this.bar);
    },
    fn2: () => {
        console.log(this);
        console.log(this.bar);
    },
}

// 普通函数
foo.fn1();

// 通过对象调用,普通函数的this会指向对象,但箭头函数的this使用的是外层函数的this
// 此处 箭头函数内的this指向全局对象
// 输出结果:window/global  undefined
foo.fn2();

小结

  • 严格模式下,全局的 this 指向 undefined ;非严格模式下,全局的 this 指向 全局对象(window/global,取决于运行环境)
  • 函数体内的 this 指向与函数在哪定义无关取决于如何调用函数
  • 箭头函数本身无 this,默认使用的是定义时的外层函数的 this

改变 this 指向

除了调用函数和箭头函数会隐式的决定*this指向外,也可以通过以下三个方法手动确定this的指向*

call 方法修改 this 指向

call 方法可以指定 this 的指向,然后在指定的作用域中指向函数。

语法:

function.call(thisArg, arg1, arg2, ...)

thisArg:可选的。在 function 函数运行时使用的 this 值。请注意,this可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动替换为指向全局对象,原始值会转换为包装类型

arg1, arg2, ...:可选值。参数列表,会传递给 function

apply 方法修改 this 指向

apply 方法与 call 方法作用完全相同,只是语法上有细微的区别:要传递给原函数的参数是一个数组,而不是多个参数。

语法:

function.call(thisArg, argsArray)

bind 方法修改 this 指向

bind 方法与 call 在语法上相同,但是 bind 方法会返回一个新函数,该函数的 this 指向 bind 方法的第一个参数

语法:

function.bind(thisArg[, arg1[, arg2[, ...]]])

小结

关于 callapply、*bind*的详细介绍及手写实现见文章 --- call、apply、bind的实际应用及实现原理