首页 > web前端 > js教程 > 掌握JavaScript的最后一步

掌握JavaScript的最后一步

Jennifer Aniston
发布: 2025-02-19 13:17:09
原创
470 人浏览过

The Final Steps to Mastering JavaScript's

前文已阐述JavaScript this关键字的基础用法。this指向的关键在于运行时上下文。然而,上下文在预期之外发生变化时,问题就出现了。本文将重点介绍这种情况,以及如何解决。

核心要点

  • JavaScript中的this关键字指向当前执行上下文,理解它对于操作和交互对象至关重要,尤其是在面向对象编程或使用大量依赖this的框架和库时。
  • this关键字的常见问题包括在提取的方法、回调函数和闭包中使用。这些问题可以通过使用bind()方法将this关键字显式绑定到正确的对象来解决。
  • ECMAScript 6引入了箭头函数,它从其直接封闭作用域获取this值。箭头函数的词法绑定无法被覆盖,使其成为维护this正确上下文更优雅的解决方案。
  • this的值取决于函数的调用方式。在方法中,this指向它所属的对象;在普通函数中,this指向全局对象;如果用new关键字(作为构造函数)调用函数,this指向新创建的对象;在事件处理程序中,this指向接收事件的元素;最后,可以使用call()apply()bind()显式设置this

解决常见问题

本节将探讨使用this关键字时出现的一些最常见问题,并学习如何解决它们。

1. 在提取的方法中使用this

最常见的错误之一是尝试将对象的方法赋值给变量,并期望this仍然指向原始对象。如下例所示,这行不通。

var car = {
  brand: "Nissan",
  getBrand: function() {
    console.log(this.brand);
  }
};

var getCarBrand = car.getBrand;

getCarBrand(); // 输出:undefined
登录后复制
登录后复制
登录后复制

即使getCarBrand似乎是car.getBrand()的引用,实际上它只是getBrand()自身的另一个引用。我们已经知道,调用位置决定上下文,此处调用位置是getCarBrand(),这是一个简单的函数调用。为了证明getCarBrand指向一个无基础的函数(未绑定到任何特定对象的函数),只需在代码底部添加alert(getCarBrand);,您将看到以下输出:

var car = {
  brand: "Nissan",
  getBrand: function() {
    console.log(this.brand);
  }
};

var getCarBrand = car.getBrand;

getCarBrand(); // 输出:undefined
登录后复制
登录后复制
登录后复制

getCarBrand只包含一个普通函数,它不再是car对象的成员方法。因此,在这种情况下,this.brand实际上转换为window.brand,当然它是未定义的。如果我们从对象中提取方法,它又变成了一个普通函数。它与对象的连接被切断,不再按预期工作。换句话说,提取的函数没有绑定到它所取自的对象。那么我们如何补救呢?如果我们想保留对原始对象的引用,我们需要在将getBrand()函数赋值给getCarBrand变量时,显式地将getBrand()函数绑定到car对象。我们可以使用bind()方法来实现。

function(){
  console.log(this.brand);
}
登录后复制
登录后复制

现在,我们得到了正确的输出,因为我们成功地将上下文重新定义为我们想要的样子。

2. 在回调函数中使用this

下一个问题发生在我们传递一个方法(使用this作为参数)作为回调函数时。例如:

var getCarBrand = car.getBrand.bind(car);
getCarBrand(); // 输出:Nissan
登录后复制

即使我们使用car.getBrand,我们实际上只得到附加到按钮对象的函数getBrand()。将参数传递给函数是隐式赋值,因此这里发生的情况与上一个示例几乎相同。不同之处在于,现在car.getBrand不是显式赋值,而是隐式赋值。结果几乎相同——我们得到的是一个普通函数,绑定到按钮对象。换句话说,当我们在一个对象上执行一个方法时,该对象与最初定义该方法的对象不同,this关键字不再指向原始对象,而是指向调用该方法的对象。参考我们的例子:我们在el(按钮元素)上执行car.getBrand,而不是它最初定义的car对象。因此,this不再指向car,而是指向el。如果我们想保持对原始对象的引用不变,同样,我们需要使用bind()方法将getBrand()函数显式绑定到car对象。

var car = {
  brand: "Nissan",
  getBrand: function() {
    console.log(this.brand);
  }
};

var el = document.getElementById("btn");
el.addEventListener("click", car.getBrand);
登录后复制

现在,一切按预期工作。

3. 在闭包内使用this

this的上下文可能出错的另一个情况是我们在闭包内使用this。考虑以下示例:

el.addEventListener("click", car.getBrand.bind(car));
登录后复制

这里的输出是undefined,因为闭包函数(内部函数)无法访问外部函数的this变量。最终结果是this.brand等于window.brand,因为内部函数中的this绑定到全局对象。为了解决这个问题,我们需要将this绑定到getBrand()函数。

var car = {
  brand: "Nissan",
  getBrand: function() {
    var closure = function() {
      console.log(this.brand);
    };
    return closure();
  }
};

car.getBrand(); // 输出:undefined
登录后复制

这种绑定等同于car.getBrand.bind(car)。另一种流行的修复闭包的方法是将this值赋值给另一个变量,从而防止意外更改。

var car = {
  brand: "Nissan",
  getBrand: function() {
    console.log(this.brand);
  }
};

var getCarBrand = car.getBrand;

getCarBrand(); // 输出:undefined
登录后复制
登录后复制
登录后复制

这里,this的值可以赋值给_thisthatselfmemycontext、对象的伪名称或任何其他适合你的名称。关键是保留对原始对象的引用。

ECMAScript 6 的救援

在前面的示例中,我们看到了所谓的“词法this”的入门知识——当我们将this值赋值给另一个变量时。在ECMAScript 6中,我们可以使用类似但更优雅的技术,通过新的箭头函数来实现。箭头函数不是由function关键字创建的,而是由所谓的“胖箭头”运算符(=>)创建的。与普通函数不同,箭头函数从其直接封闭作用域获取this值。箭头函数的词法绑定无法被覆盖,即使使用new运算符也是如此。现在让我们看看如何使用箭头函数来替换var self = this;语句。

function(){
  console.log(this.brand);
}
登录后复制
登录后复制

关于this需要记住的内容

我们看到this关键字,就像其他任何机制一样,遵循一些简单的规则,如果我们很好地了解这些规则,那么我们可以更自信地使用该机制。因此,让我们快速回顾一下我们已经学到的内容(来自本文和前文):

  • 在以下情况下,this指向全局对象:
    • 在最外层上下文,在任何函数块之外。
    • 在不是对象方法的函数中。
    • 在不是对象构造函数的函数中。
  • 当函数作为父对象的属性调用时,this指向父对象。
  • 当使用call()apply()bind()调用函数时,this指向传递给这些方法的第一个参数。如果第一个参数为null或不是对象,则this指向全局对象。
  • 当使用new运算符调用函数时,this指向新创建的对象。
  • 当使用箭头函数(在ECMAScript 6中引入)时,this依赖于词法作用域并指向父对象。

了解这些简单明了的规则,我们可以轻松预测this将指向什么,如果它不是我们想要的,我们就知道可以使用哪些方法来修复它。

总结

JavaScript 的this关键字是一个难以掌握的概念,但只要多加练习,你就能掌握它。我希望本文和我的上一篇文章能作为你理解的基础,并在下次this让你头疼时成为有价值的参考。

JavaScript this关键字的常见问题解答 (FAQs)

(此处省略了FAQs部分,因为篇幅过长,且与前面内容高度重复。FAQs部分内容已在前面详细解释。)

以上是掌握JavaScript的最后一步的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板