切换语言为:繁体

理解JavaScript 中的难点: this关键字

  • 爱糖宝
  • 2024-10-16
  • 2034
  • 0
  • 0

今天我在学习手写 Promise 的过程中又遇到了 this。说实话,作为从业三年的开发者,this 一直是个让我头疼的问题,尤其对于我这个用了三年的 React 函数式组件的人来说,this 的指向总是变来变去。我常常困惑于它到底指向了什么、为什么要用它。可是,当我尝试继续深入理解 Promise 时,发现绕不开 this 这个概念。没办法,只能硬着头皮学下去了。既然如此,我们就一起来揭开这个在 JavaScript 中根深蒂固的“谜题”。

this 是 JavaScript 中一个复杂且重要的概念,它的指向是动态的,取决于函数的调用方式。要彻底理解 this,我们需要深入了解它在不同场景下的表现。接下来,我将通过几个不同的例子帮助你全面理解 this 的使用。

1. 普通函数中的 this

在普通函数中,this 的指向取决于谁调用了这个函数,它在调用阶段动态绑定。例如:

function showThis(){
  console.log(this);  // 浏览器中是 window,Node.js 中是 global
}
showThis();

在这个例子中,showThis 是在全局环境中执行的,相当于全局环境调用了这个函数,因此 this 的指向是全局对象。

如果在对象的方法中调用函数,调用者是该对象,那么 this 的指向就是该对象:

const obj = {
    a: 1,
    b: function(){
        console.log(this.a);  // 输出 1
    }
}
obj.b();

注意:在严格模式 ('use strict') 下,如果 this 没有显式绑定,它的指向会是 undefined

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

2. 箭头函数中的 this

箭头函数与普通函数不同,它的 this 在定义时就已经确定了。箭头函数不会创建自己的 this,而是继承自定义时所在的作用域。看看下面的例子:

function Outer(){
    this.name = 'outer';
    
    const regularFunction = function(){
        console.log(this.name);  // 非严格模式下为 undefined,严格模式下同样为 undefined
    }

    const arrowFunction = () => {
        console.log(this.name);  // 输出 'outer'
    }

    regularFunction();
    arrowFunction();
}

new Outer();

在这个例子中,箭头函数 arrowFunction 继承了 Outer 的作用域,因此 this 指向 Outer 的实例。而普通函数 regularFunction 没有继承 Outerthis,所以 this.name 输出 undefined

对象中的箭头函数也是类似的:

const obj = {
    a: 1,
    b: function(){
        const output = () => {
            console.log(this.a);  // 输出 1
        }
        output();
    }
}
obj.b();

在这个例子中,箭头函数 output 继承了 b 方法的 this,因此 this.a 输出的是 obj.a

3. 显式绑定:callapplybind

上面提到的例子都是隐式绑定,即 this 自动绑定到调用者。接下来我们看看显式绑定,即通过 callapplybind 来手动控制 this 的指向。

1. call()apply()

callapply 都会立即调用函数,它们的区别在于参数传递方式不同:

  • call:参数以逗号分隔传递。

  • apply:参数以数组形式传递。

例如:

function greet(greeting, punctuation) {
    console.log(greeting + ', ' + this.name + punctuation);
}

const person = { name: 'Bob' };

greet.apply(person, ['Hi', '.']);  // 输出 "Hi, Bob."
greet.call(person, 'Hello', '!');  // 输出 "Hello, Bob!"

2. bind()

bindcallapply 不同,它不会立即调用函数,而是返回一个新函数,这个新函数的 this 永远绑定到 bind() 的第一个参数。你可以传递参数给 bind(),这些参数会在调用新函数时依次传入。

例如:

function greet(greeting, punctuation) {
  console.log(greeting + ', ' + this.name + punctuation);
}

const person = { name: 'Charlie' };

// 使用 bind 创建一个新的函数,this 永远绑定到 person
const boundGreet = greet.bind(person, 'Hey');

// 调用绑定的函数
boundGreet('!!');  // 输出 "Hey, Charlie!!"


总结

this 是 JavaScript 中一个动态的概念,它的指向取决于函数的调用方式。在普通函数中,this 的指向取决于谁调用了该函数;而在箭头函数中,this 会继承定义时的上下文。此外,通过 callapplybind,我们可以显式地控制 this 的指向。理解 this 是掌握 JavaScript 高级特性的关键,尤其是在编写复杂的异步代码和组件库时。


通过这些场景的例子,你应该能够更好地理解 this 在 JavaScript 中的表现,进而更加自信地在项目中使用它!

0条评论

您的电子邮件等信息不会被公开,以下所有项均必填

OK! You can skip this field.