前端百题斩【014】——js中的这些“this”指向都值得了解

写该系列文章的初衷是“让每位前端工程师掌握高频知识点,为工做助力”。这是前端百题斩的第14斩,但愿朋友们关注公众号“执鸢者”,用知识武装本身的头脑。

img

14.1 简介

this是javascript中的一个关键字,其使用方法相似于一个变量,是执行上下文中一个重要组成部分。其做用是能够在函数体内部获取当前的运行环境。

14.2 指向

每一个函数的this是在调用的时候基于函数的执行环境绑定的,this的指向彻底取决于函数的调用位置。(下面均是在浏览器环境下进行测试的结果)
  1. 在全局环境下,this 始终指向全局对象(window), 不管是否严格模式;
console.log(this); // window
  1. 普通函数内部的this分两种状况,严格模式和非严格模式。

​ (1)非严格模式下,this 默认指向全局对象windowjavascript

​ (2)严格模式下, this为undefinedhtml

function fun() {
    console.log(this); // window
}
  1. 对象内部方法的this指向调用这些方法的对象前端

    (1)函数的定义位置不影响其this指向,this指向只和调用函数的对象有关;java

    (2)多层嵌套的对象,内部方法的this指向离被调用函数最近的对象(window也是对象,其内部对象调用方法的this指向内部对象, 而非window)。数组

const obj = {
    a: 10,
    b: 20,
    add: function () {
        return this.a + this.b;
    }
};

console.log(obj.add()); // 30
const add = obj.add;
console.log(add()); // NaN
  1. 原型链中的方法的this仍然指向调用它的对象
const obj = {
    a: 10,
    b: 20
};

const prototypeObj = {
    add: function () {
        return this.a + this.b;
    }
};

Object.setPrototypeOf(obj, prototypeObj);

console.log(obj.add()); // 30
  1. 构造函数中的this与被建立的新对象绑定。
function Fun() {
    this.a = 10;
}

const fun = new Fun();
console.log(fun.a); // 10
  1. 当函数经过Function对象的原型中继承的方法 call() 和 apply() 方法调用时, 其函数内部的this值可绑定到 call() & apply() 方法指定的第一个对象上, 若是第一个参数不是对象,JavaScript内部会尝试将其转换成对象而后指向它。(见后续代码)
  2. 经过bind方法绑定后, 函数将被永远绑定在其第一个参数对象上, 而不管其在什么状况下被调用。(见后续代码)
  3. 当函数被当作监听事件处理函数时, 其 this 指向触发该事件的元素(针对于addEventListener事件)
<button id="testId">按钮</button>

const btn = document.getElementById('testId');
btn.addEventListener('click', function() {
    console.log(this); // <button id="testId">按钮</button>
});
  1. 内联事件中的this指向分两种状况:浏览器

    (1)当代码被内联处理函数调用时,它的this指向监听器所在的DOM元素前端工程师

    <button onclick="console.log(this)">按钮</button> // 输出该DOM节点

(2)当代码被包括在函数内部执行时,其this指向等同于 函数直接调用的状况,即在非严格模式指向全局对象window, 在严格模式指向undefinedapp

<button onclick="clickFun()">按钮</button>

function clickFun() {
    console.log(this); // window
}
  1. 对于延时函数内部的回调函数的this指向全局对象window(固然能够经过bind方法改变其内部函数的this指向)
function Fun() {
    this.a = 10;
    this.method = function() {
        setTimeout(function() {
            console.log(this); // window
        }, 1000);
    }
}

const fun = new Fun();
fun.method();
  1. 因为箭头函数不绑定this, 它会捕获其所在(即定义的位置)上下文的this值, 做为本身的this值,因此 call() / apply() / bind() 方法对于箭头函数来讲只是传入参数,对它的 this 毫无影响。
function Fun() {
    this.a = 10;
    this.method = function() {
        setTimeout(() => {
            console.log(this); // Fun {a: 10, method: ƒ}
        }, 1000);
    }
}

const fun = new Fun();
fun.method();

14.3 改变this指向

除了隐式绑定this的方式,还可以经过显示绑定的方式,经过call、apply、bind方式改变this指向,对于这三者的区别后续将有专门的百题斩去阐述,本节主要进行一波简单使用。
  1. call()
call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。
function method(val1, val2) {
    return this.a + this.b + val1 + val2;
}

const obj = {
    a: 1,
    b: 2
};

console.log(method.call(obj, 3, 4)); // 10
  1. apply()
apply() 方法调用一个具备给定 this值的函数,以及以一个数组(或类数组对象)的形式提供的参数。
function method(val1, val2) {
    return this.a + this.b + val1 + val2;
}

const obj = {
    a: 1,
    b: 2
};

console.log(method.apply(obj, [3, 4])); // 10
  1. bind()
bind() 方法建立一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其他参数将做为新函数的参数,供调用时使用。
function method(val1, val2) {
    return this.a + this.b + val1 + val2;
}

const obj = {
    a: 1,
    b: 2
};

const bindMethod = method.bind(obj, 3, 4);
console.log(bindMethod); // [Function: bound method]
console.log(bindMethod()); // 10
扩展
  1. call()apply()的区别是call()方法接受的是参数列表,而apply()方法接受的是一个参数数组
  2. bind返回的是一个绑定函数,而call和apply返回的是运行结果;
  3. 屡次 bind() 是无效的,只会绑定到第一次调用的对象上;
  4. call() / apply() / bind() 方法对于箭头函数来讲只是传入参数,对它的 this 毫无影响。

1.若是以为这篇文章还不错,来个分享、点赞吧,让更多的人也看到函数

2.关注公众号执鸢者,与号主一块儿斩杀前端百题。测试