资讯专栏INFORMATION COLUMN

你应该要知道的JS中的this

edgardeng / 3377人阅读

摘要:在用创建对象时,指向发生改变是在第二步创建一个对象实例将构造函数中的指向这个对象执行构造函数中的代码返回这个新创建的对象箭头函数中的箭头函数内部是不会绑定的,它会捕获外层作用域中的,作为自己的值。参考你不知道的上卷

前言

this 是 JavaScript 中不可不谈的一个知识点,它非常重要但又不容易理解。因为 JavaScript 中的 this 不同于其他语言。不同场景下的 this 指向不同(当函数被调用执行时会生成变量对象,确定 this 的指向,因此当前函数的 this 是在函数被调用执行的时候才确定的,所以导致 this 的指向灵活不确定),而且,在严格模式和非严格模式下,this 也会有不同的解读。

为什么要有 this

先想想如果 JavaScript 中没有 this 会怎么样?比如下面这段代码:

function identity(context) {
    return context.name.toUpperCase();
}
function speak(context) {
    var greeting = "Hello, I am " + identity(context)
    console.log(greeting)
}
var you = {
    name: "Reader"
}
var me = {
    name: "Stone"
}
identity(you); // READER
speak(me); // Hello, I am Stone

我们给这 identity 和 speak 两个函数显示的传入了一个上下文对象,这似乎看不出什么,但是一旦你的应用变得越来越复杂,这种显示传递上下文就会让代码越来越混乱,代码结构越来越模糊。而使用 this 就可以避免这样,因为 this 提供了一种更优雅的方式来隐式传递对象引用,可以把 API 设计得更加简洁易用。

this 的绑定规则 全局对象中的 this

全局对象的变量对象是一个比较特殊的存在,在全局对象中,this 指向它本身,比如:

// this 绑定到全局对象
this.a1 = 10;

// 通过声明绑定到变量对象,全局环境中,变量对象就是它本身
var a2 = 20;

// 会隐式绑定到全局对象
a3 = 30;

console.log(a1); // 10
console.log(a2); // 20
console.log(a3); // 30
函数中的 this

在一个函数的执行上下文中,this 由该函数的调用者提供,由函数的调用方式来决定 this 的指向。下面这个例子:

function fn() {
    console.log(this)
}
fn(); // Window {...}

默认全局对象就是调用者,等价于 window.fn()(只讨论浏览器中全局对象)。但是在非严格模式中,this 是指向 undefined 的,比如:

"use strict";
function fn() {
    console.log(this);
}
fn(); // undefined
window.fn(); // Window {...}

这就说明了,如果不指定函数调用者,在严格模式下回默认绑定到全局对象,在非严格模式下默认指向 undefined 。

函数是独立调用,还是被某个对象所调用,是很容易分辨的,比如:

"use strict";
var a = 20;
function fn() {
    var a = 1;
    var obj = {
        a: 10,
        c: this.a + 20
    }
    return obj.c
}
console.log(window.fn()); // 40
console.log(fn()); // TypeError

对象字面量的形式不会产生自己的作用域,所以 obj 中的 this.a 并不是指向 obj ,而是与函数内部的 this 一样。因此,当 window.fn() 调用时,fn 内部的 this 指向 window 对象,此时 this.a 访问全局对象中的 a ;由于是在严格模式中,在没有指明调用者的时候,fn 内部默认指向 undefined,所以在多带带调用的时候会报错。

call/apply/bind 显示绑定 this

JavaScript 中提供了一个方式可以让我们手动指定函数内部的 this 指向,也就是前面提到的隐式传递对象,它们就是call/apply/bind。这三个方法是 Function 的原型方法,所有函数都可以调用这三个方法。看下面这个例子:

var a = 20;
var obj = {
    a: 40
}
function fn() {
    console.log(this.a);
}
fn(); // 20
fn.call(obj); // 40
fn.apply(obj); // 40

当函数调用 apply/bind 时,表示执行该函数,并且这个函数内部的 this 指向 apply/bind 的第一个参数。

二者的区别:

call 的第一个参数是函数内部 this 的指向,后续的参数则是函数执行时所需要的参数,一个一个传递

apply 的第一个参数与 call 相同,而执行函数的参数,则以数组的形式传入

bind 方法也能指定函数的 this ,但是它不同于call/apply。bind 方法会返回一个新函数,这个函数与原函数有相同的函数体,但是函数内部的 this 被绑定成 bind 方法的第一个参数,后续参数也是一个一个传入,并且不会自动执行新函数。

构造函数中的 this

可以把构造函数看成是普通函数,其中的 this 指向是创建的对象实例,之所以称之为构造函数,是因为我们会借助 new 操作符来调用函数。在用 new 创建对象时,this 指向发生改变是在第二步:

创建一个对象实例

将构造函数中的 this 指向这个对象

执行构造函数中的代码

返回这个新创建的对象

function Foo() {
    this.a = 20
}
var foo = new Foo()
console.log(foo.a) // 20
箭头函数中的 this

箭头函数内部是不会绑定 this 的,它会捕获外层作用域中的 this,作为自己的 this 值。比如:

function Person() {
  this.age = 20;
  (() => {
    this.age++
  })()
}
var p = new Person()
console.log(p.age)
DOM事件中的 this

当函数被当做监听事件处理函数时, 其 this 指向触发该事件的元素 (针对于addEventListener事件)。比如:

click
document.querySelector(".box").addEventListener("click", function(e) {
  console.log(this) // 这个this指向div.box元素
}, false)
总结

this 的使用场景丰富多样,可以用来实现继承,实现函数柯里化等,作为开发者应该清楚各种使用方式以及其内部原理。

参考

你不知道的JavaScript(上卷)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/101080.html

相关文章

  • 翻译连载 |《知道JS》姊妹篇 |《JavaScript 轻量级函数式编程》- 第 2 章:函

    摘要:从某些方面来讲,这章回顾的函数知识并不是针对函数式编程者,非函数式编程者同样需要了解。什么是函数针对函数式编程,很自然而然的我会想到从函数开始。如果你计划使用函数式编程,你应该尽可能多地使用函数,而不是程序。指的是一个函数声明的形参数量。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson - 《You-Dont-Know-JS》作者 关于译者:...

    Riddler 评论0 收藏0
  • this总结【1】—— this概览

    摘要:是什么这个单词是一个代词,所以应该是指代某些东西搞清楚的关键之处,就是要搞清楚指代了什么那么到底指代了什么呢就像你平时指着一个苹果说指着一个香蕉说同样,也会因为情况的不同而不同在中按照常规理解,的值是什么取决于函数如何被调用然而,的值是什么 1. this是什么 this这个单词是一个代词,所以this应该是 指代某些东西搞清楚this的关键之处,就是要搞清楚this指代了什么 那么t...

    MyFaith 评论0 收藏0
  • JavaScript深入浅出

    摘要:理解的函数基础要搞好深入浅出原型使用原型模型,虽然这经常被当作缺点提及,但是只要善于运用,其实基于原型的继承模型比传统的类继承还要强大。中文指南基本操作指南二继续熟悉的几对方法,包括,,。商业转载请联系作者获得授权,非商业转载请注明出处。 怎样使用 this 因为本人属于伪前端,因此文中只看懂了 8 成左右,希望能够给大家带来帮助....(据说是阿里的前端妹子写的) this 的值到底...

    blair 评论0 收藏0
  • [译]理解设计模式

    摘要:例如可以用构造函数实现单例模式。例如当这个构造函数被调用,它会检查是否存在。工厂模式工厂模式使用工厂方法创建对象,而不指定所创建对象的确切类或构造函数。虽然了解审设计模式很重要,但是不要过度使用它们。 By Sukhjinder Arora | Oct 16, 2018 原文 当你开始了一个新项目,你不会马上开始编写代码。第一步,你必须定义这个项目解决什么问题和适用范围,然后列出这个项...

    NeverSayNever 评论0 收藏0

发表评论

0条评论

edgardeng

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<