作为前端开发者,我们都知道 this
是 JavaScript 中一个非常重要的关键字,也是初学者常常觉得困惑的语法之一。实际上,在 ECMAScript 2021 中,this
依然是一个容易被忽略难点。在本文中,我们将深入探讨 this 的用法和难点,并提供一些实际的例子和指导意义。
什么是 this?
this
是指向当前函数执行的环境对象的一个关键字。它与普通变量的区别在于,它的值在函数调用的时候才能确定。
在 JavaScript 中,有四种情况下使用 this
:
- 函数作为对象的方法调用,
this
指向这个对象
const person = { name: 'Tom', sayName() { console.log(this.name); } } person.sayName(); // 'Tom'
- 直接调用函数,
this
指向window
或global
function sayName() { console.log(this.name); } sayName(); // undefined
- 通过
apply
,call
或bind
改变函数的上下文,this
指向指定的对象
-- -------------------- ---- ------- ----- ------- - - ----- ----- - ----- ------- - - ----- ------- - -------- --------- - ----------------------- - ---------------------- -- ----- ----------------------- -- ------- ----- ---------- - ---------------------- ------------- -- -----
- 作为构造函数调用,
this
指向新创建的对象
function Person(name) { this.name = name; this.sayName = function() { console.log(this.name); } } const person = new Person('Tom'); person.sayName(); // 'Tom'
ECMAScript 2021 的新特性
在 ECMAScript 2021 中,新增了一些关于 this
的特性,让我们更加方便地使用它。
箭头函数的 this
在普通函数中,this
的值是在函数被调用的时候决定的。而在箭头函数中,this
的值是在声明时决定的。这意味着,在箭头函数中使用 this
时,它指向的是函数声明时所在的上下文。
-- -------------------- ---- ------- ----- ------ - - ----- ------ --------- - ----- -------- - -- -- - --------------------- - - --------- -- ----------- - - ----------------- -- ---- -------
在这个例子中,我们定义了一个箭头函数 fullName
,并在 sayName
中调用它。由于 fullName
是在 sayName
中定义的,而 sayName
是作为 person
对象的方法调用的,所以 this
指向的是 person
对象。因此,this.name
的值为 'Tom'
。
静态方法的 this
在 ECMAScript 2021 中,我们可以使用 this
来引用静态方法内部的其他静态方法,而不必使用类名或对象名。这种方式使得代码更加可读且易于维护。
-- -------------------- ---- ------- ----- ------ - ------ ---------- - ------------------- - - ------------------ - ------ --------- - ------ ------ - - ------------------ -- ------- ----
在这个例子中,我们定义了一个 Person
类,其中包含两个静态方法 sayHello
和 getName
。我们可以看到,在 sayHello
中使用了 Person.getName
来调用 getName
方法。而在 ECMAScript 2021 中,我们可以使用 this.getName()
来代替 Person.getName()
。这种方式使得代码更加清晰易懂。
经典难题:this
指向问题
尽管我们已经了解了 this
的基本用法和 ECMAScript 2021 中的新特性,但仍然有一些比较经典的难点仍然需要深入探讨。下面是其中几个例子:
setTimeout
中的 this
const person = { name: 'Tom', sayName() { console.log(this.name); } } setTimeout(person.sayName, 1000); // undefined
在这个例子中,我们定义了一个 person
对象,并调用了它的 sayName
方法。我们还通过 setTimeout
函数来实现延迟执行。然而,我们将 person.sayName
传递给 setTimeout
,这样在执行 sayName
方法的时候,this
就变成了 window
。因此控制台输出 undefined
,而不是 'Tom'
。
解决这个问题的方法是通过箭头函数来定义一个包裹函数,将 person.sayName
作为参数传递进去。这样,在执行箭头函数的时候,this
仍然指向 person
对象。
setTimeout(() => { person.sayName(); }, 1000); // 'Tom'
点击事件中的 this
const button = document.querySelector('button'); button.addEventListener('click', function() { console.log(this); }); // <button>Click me!</button>
在这个例子中,我们使用 addEventListener
函数为按钮添加了一个点击事件监听。我们还定义了一个匿名函数来作为点击事件回调函数,用于输出当前的 this
对象。然而,在这种情况下,this
实际上指向的是触发事件的 DOM 元素(即按钮),而不是我们希望的回调函数内部定义的 this
。这可能会导致一些错误,例如无法访问我们希望的对象。
解决这个问题的方法是使用箭头函数。箭头函数中的 this
始终指向定义时所在的上下文,而不是执行时的上下文。因此,使用箭头函数来定义回调函数可以解决这个问题。
const button = document.querySelector('button'); button.addEventListener('click', () => { console.log(this); }); // Window {...}
map
中的 this
-- -------------------- ---- ------- ----- ------ - - ----- ------ -------- --------- ------- -------- ------------- - --------------------------------- - --------------------- - - --- -- -- - - -------- --- - - --------------------- -- --------- --- -- -- ----- -- --------- --- -- -- ---- -- --------- --- -- -- ----
在这个例子中,我们定义了一个 person
对象,它有一个 listFriends
方法,用于遍历所有朋友,并向他们问好。我们在 map
中使用了一个匿名函数来实现,但是在匿名函数中,this
的值已经改变,不再指向 person
对象。
解决这个问题的方法是使用箭头函数。箭头函数中的 this
始终指向定义时所在的上下文,而不是执行时的上下文。因此,使用箭头函数来定义回调函数可以解决这个问题。
-- -------------------- ---- ------- ----- ------ - - ----- ------ -------- --------- ------- -------- ------------- - ------------------------- -- - --------------------- - - --- -- -- - - -------- --- - - --------------------- -- --- --- -- -- ----- -- --- --- -- -- ---- -- --- --- -- -- ----
总结
本文深入探讨了 this
的基本用法和 ECMAScript 2021 中的新特性,并给出了一些经典难题的解决方案。通过深入探讨和实际的例子,我们可以更好地理解 this
的概念和用法,也可以更加高效地使用它来开发我们的前端应用程序。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/646ed525968c7c53b0d37a92