还在晕this指向吗来看看这篇

153 阅读2分钟

我们来看看this调用的几种情况,或者说,应该注意的几种情况

1. 全局上下文

在全局执行环境中(即不在任何函数内部),this 指向全局对象:

  • 在浏览器中,this 指向 window 对象。
  • 在 Node.js 环境中,this 指向 global 对象。
  • 在严格模式 ('use strict') 下,this 将是 undefined
console.log(this); // 浏览器中:Window {...}

2. 函数调用

当一个函数被直接调用时(即不通过对象或构造函数调用),this 在非严格模式下指向全局对象,在严格模式下为 undefined

function foo() {
    console.log(this);
}

foo(); // 非严格模式下:Window {...};严格模式下:undefined

3. 方法调用

当函数作为对象的方法调用时,this 指向调用该方法的对象。

const obj = {
    method: function() {
        console.log(this);
    }
};

obj.method(); // 输出 obj

4. 构造函数调用

当使用 new 关键字调用函数时,它被视为构造函数,此时 this 指向新创建的对象实例。

function Constructor() {
    this.value = 'constructed';
}

const instance = new Constructor();
console.log(instance.value); // 'constructed'

5. call, apply, 和 bind

这些方法允许显式设置 this 的值:

  • callapply 立即调用函数,并将第一个参数作为 this 值传递给函数。
  • bind 返回一个新的函数,该函数的 this 值被永久绑定到传入的第一个参数。
function greet(greeting) {
    console.log(`${greeting}, ${this.name}`);
}

const person = { name: 'Alice' };

greet.call(person, 'Hello'); // Hello, Alice
greet.apply(person, ['Hi']); // Hi, Alice

const greetPerson = greet.bind(person);
greetPerson('Hey'); // Hey, Alice

6. 箭头函数

箭头函数没有自己的 this 绑定,而是继承自外层作用域(词法作用域)。

const obj = {
    name: 'Bob',
    greet: () => {
        console.log(`Hello, ${this.name}`); // this 指向全局对象或 undefined (严格模式)
    }
};

obj.greet(); // Hello, undefined (严格模式)

// 使用普通函数可以正确获取 this
const obj2 = {
    name: 'Charlie',
    greet: function() {
        console.log(`Hello, ${this.name}`); // this 指向 obj2
    }
};

obj2.greet(); // Hello, Charlie

ok同学们这里思考一个问题,继承自外层,那么外层是指什么意思,如果不是很懂的话,我们来看这两行代码

const obj = {
    name: 'Bob',
    greet: (() => {
        console.log(`Hello, ${this.name}`); // this 指向全局对象或 undefined (严格模式)
    })()
};

解释:

  1. 箭头函数与 this

    • 箭头函数没有自己的 this 绑定,而是继承自外层作用域(词法作用域)。这意味着在箭头函数内部,this 将指向定义该函数时所在的上下文,而不是调用时的上下文。
  2. 立即执行函数表达式 (IIFE)

    • 这行代码中,箭头函数是一个立即执行的函数表达式(IIFE),并且它在对象字面量内部被定义和调用。
    • 由于它是立即执行的,因此它会在定义时立即运行,而不会等待 obj.greet 被调用。
  3. this 的值

    • 在这个 IIFE 中,this 的值取决于外部作用域。如果这段代码是在全局作用域中执行的,那么 this 将指向全局对象(浏览器中的 window 或 Node.js 中的 global)。如果是在严格模式下,则 thisundefined
  • 如果这段代码在非严格模式下的全局作用域中执行,this 将指向全局对象,因此 this.name 可能是 undefined(除非全局作用域中有一个名为 name 的变量)。
  • 如果是在严格模式下,this 将是 undefined,因此 this.name 也将是 undefined

示例输出:

假设这段代码在严格模式下运行:

'use strict';

const obj = {
    name: 'Bob',
    greet: (() => {
        console.log(`Hello, ${this.name}`); // 输出:Hello, undefined
    })()
};

使用普通方法:

const obj = {
    name: 'Bob',
    greet() {
        console.log(`Hello, ${this.name}`); // 输出:Hello, Bob
    }
};

obj.greet();

使用函数表达式:

const obj = {
    name: 'Bob',
    greet: function() {
        console.log(`Hello, ${this.name}`); // 输出:Hello, Bob
    }
};

obj.greet();

使用箭头函数但不立即执行:

如果您坚持使用箭头函数,可以将其定义为对象的方法,但不要立即执行:

const obj = {
    name: 'Bob',
    greet: () => {
        console.log(`Hello, ${this.name}`); // 注意:这里的 this 不是指向 obj
    }
};

obj.greet(); // 输出:Hello, undefined (因为箭头函数的 this 指向定义时的上下文)

要让箭头函数正确引用 obj,可以将 obj 显式传递给箭头函数:

const obj = {
    name: 'Bob',
    greet: (() => {
        const self = obj;
        return () => console.log(`Hello, ${self.name}`);
    })()
};

obj.greet(); // 输出:Hello, Bob

所以看到这里大家应该知道了这个外层是什么意思,意思就是外层的词法作用域,也就是花括号{},ok我们继续下一步

7. 事件处理程序

在 DOM 事件处理程序中,this 通常指向触发事件的元素。

<button id="myButton">Click me</button>
<script>
document.getElementById('myButton').addEventListener('click', function() {
    console.log(this); // <button> element
});
</script>

8. 立即执行函数表达式 (IIFE)

在 IIFE 中,this 指向全局对象(非严格模式)或 undefined(严格模式)。

(function() {
    'use strict';
    console.log(this); // undefined
})();

this 的值依赖于函数的调用方式。通过使用 callapplybind 可以显式控制 this 的值,而在使用箭头函数时要注意它们不会创建自己的 this 上下文。