写点什么

JavaScript 开发人员应该理解的 this

用户头像
devpoint
关注
发布于: 13 小时前
JavaScript 开发人员应该理解的 this

初次接触 this 是在 c# 中,再后来的 JavaScript ,两者在 this 处理上非常相似。但是 JavaScript 是一种基于原型的编程语言,没有类的概念。意味着 this 将指向调用函数的对象,通常称为上下文。当然 this 不止于此,在函数内部的引用可以绑定到不同的对象,这得取决于函数是从哪里被调用。this 问题和变量函数提升是前端面试常见的问题,关于变量提升可以参阅《加深Javascript变量函数声明提升理解

绑定

在 JavaScript 中,词法环境(Lexical Environments)是一种规范类型,用于根据 ECMAScript 代码的词法嵌套结构定义标识符与特定变量和函数的关联。一个词法环境由一个环境记录(Environment Record)和一个可能为空的外部词法环境的引用组成。通常,词法环境与 ECMAScript 代码的特定句法结构有关。例如函数申明、块语句、try语句中的catch等代码每次运算后会产生新的词法环境。


执行上下文(Execution Contexts)是一种规范设备,通过 ECMAScript 编译器来跟踪代码的运行时评估。在任何时候,每个代理(agent)最多只有一个正在执行代码的执行上下文。


每个执行上下文包含一个环境记录(Environment Record),当 JavaScript 引擎执行代码时,变量和函数名会被添加到环境记录(Environment Record)中,这就是绑定的基本概念,有助于将标识符(变量、函数名)与执行上下文的 this 关键字关联起来。

函数调用

这个很简单,this 是指调用的来源,在函数中的 this 指的是全局对象。


function callAuthor() {    console.log(this.author);}
callAuthor(); // undefined
var author = "DevPoint";
callAuthor(); // DevPoint
复制代码


在严格模式下,this.author 的值为 undefined

let & const

如果在全局级使用 letconst 声明变量,则它们不会存储在全局对象中。相反,在不可访问的声明性环境记录中,因此前面的示例在使用 const 时输出不一样的结果。


function callAuthor() {    console.log(this.author);}
const author = "DevPoint";callAuthor(); // undefinedwindow.author = "DevPoint";callAuthor(); // DevPoint
复制代码

隐式绑定

当函数引用有上下文对象时,隐式绑定规则会把函数中的 this 绑定到这个上下文对象。对象属性引用链中只有上一层或者说最后一层在调用中起作用。


const thisArticle = {    title: "JavaScript",    printTitle: function () {        console.log(this.title);    },};
thisArticle.printTitle(); // JavaScript
复制代码


如果对象只包含对 printTitle 调用函数的引用,可以获得相同的结果:


function printTitle() {    console.log(this.title);}
const thisArticle = { title: "JavaScript", printTitle: printTitle,};
thisArticle.printTitle(); // JavaScript
复制代码

显式绑定

通过callapplybind 方法把对象绑定到 this 上,叫做显式绑定。


function article() {    console.log(this.title);}
const thisArticle = { title: "JavaScript",};
article.call(thisArticle); // JavaScript
复制代码


callapply 都执行相同的操作,两者的第一个论点应该是这指向什么。如果需要将额外的参数传递给被调用的函数,则会出现差异。


  • 使用 call 时参数作以普通逗号分隔的参数列表传递

  • 使用 apply 时参数以数组方式传递

  • 使用 bind 将创建一个新函数并将其永久绑定到 this


下面创建一个将 this 永久绑定到 thisArticle 的新函数,并将 article 重新分配给该新的永久绑定函数:


function article() {    console.log(this.title);}
const thisArticle = { title: "JavaScript",};
const newArticle = article.bind(thisArticle);newArticle(); // JavaScript
复制代码

new 绑定

new 关键字构造一个新对象, this 指向它。当使用 new 关键字将函数作为构造函数调用时, this 指向创建的新对象。


function Article(title) {    this.title = title;}
const thisArticle = new Article("JavaScript");
console.log(thisArticle.title); // JavaScript
复制代码

箭头函数

使用箭头函数,this 保持与其父作用域相同的值。例如,箭头函数中的 this 值与外面 Article 函数中的 this 值保持一致:


function Article(title) {    this.title = title;    this.toUpper = () => {        return this.title.toUpperCase();    };}
const thisArticle = new Article("JavaScript");
console.log(thisArticle.title); // JavaScript
console.log(thisArticle.toUpper()); // JAVASCRIPT
复制代码

结论

JavaScript 中的 this 是一个容器带来 Bug 的关键字,为了减少类似问题就需要加深对其 this 的理解。从上面的介绍来看,最佳的实践是尽量使用箭头函数。


发布于: 13 小时前阅读数: 3
用户头像

devpoint

关注

细节的追求者 2011.11.12 加入

专注前端开发,用技术创造价值!

评论

发布
暂无评论
JavaScript 开发人员应该理解的 this