返回顶部
首页 > 资讯 > 前端开发 > JavaScript >js词法作用域与this实例详解
  • 786
分享到

js词法作用域与this实例详解

2024-04-02 19:04:59 786人浏览 独家记忆
摘要

目录前言实践总结前言 静态作用域又叫做词法作用域,采用词法作用域的变量叫词法变量。词法变量有一个在编译时静态确定的作用域。词法变量的作用域可以是一个函数或一段代码,该变量在这段代码区

前言

静态作用域又叫做词法作用域,采用词法作用域的变量叫词法变量。词法变量有一个在编译时静态确定的作用域。词法变量的作用域可以是一个函数或一段代码,该变量在这段代码区域内可见(visibility);在这段区域以外该变量不可见(或无法访问)。词法作用域里,取变量的值时,会检查函数定义时的文本环境,捕捉函数定义时对该变量的绑定。大多数现在程序设计语言都是采用静态作用域规则,如 C/C++C#python 、 Java 、 javascript …… 相反,采用动态作用域的变量叫做动态变量。只要程序正在执行定义了动态变量的代码段,那么在这段时间内,该变量一直存在;代码段执行结束,该变量便消失。这意味着如果有个函数 f,里面调用了函数 g,那么在执行 g 的时候,f 里的所有局部变量都会被 g 访问到。而在静态作用域的情况下,g 不能访问 f 的变量。动态作用域里,取变量的值时,会由内向外逐层检查函数的调用链,并打印第一次遇到的那个绑定的值。显然,最外层的绑定即是全局状态下的那个值。采用动态作用域的语言有 Pascal 、 EMacs Lisp 、 Common Lisp (兼有静态作用域)、 Perl (兼有静态作用域)。C/c++ 是静态作用域语言,但在宏中用到的名字,也是动态作用域。

实践

思考这么一段代码:

function fun1() {
  var a = 2
  console.log(a)
}

function fun2() {
  var a = 3
  console.log(a)
  fun1()
}
 fun2()

答案会是多少呢?


2

当然这个很好理解,js 是函数作用域,fun1 内有 a,当然会打印 fun1 内的 a 的值,并没有特殊之处,可是这个代码呢:

var a = 2
function fun1() {
  console.log(a)
}

function fun2() {
  var a = 3
  console.log(a)
  fun1()
}
 fun2()

答案和之前依旧一样,是不是这样就有点反直觉了? fun1 内没有 a 的情况下不是应该读取 fan2 的 a 吗?为什么会读取 全局作用域的 a 呢?说好的作用域是一层一层向上的呢?

当然,作用域确实是向上查找,可是 js 是静态作用域(词法作用域),并不是动态作用域,所以他不会看函数的调用位置,而是定义位置,并且沿着定义位置向上查找。词法作用域和动态作用域的区别如下:

  • 词法作用域是在 代码解析(定义) 的时候确定的,关注的是函数在 何处定义 ,并从定义处向上查找作用域。
  • 动态作用域是在 代码运行 的时候确定的,关注的是代码在 何处调用 ,并从调用栈向上查找作用域。

所以现在很好理解,为什么 fun1 内没有 a 他会先去读取全局的 a,而不是 fun2 的 a 了吧?不信可以看这个代码:

function fun1() {
  console.log(a) // a is not defined
}

function fun2() {
  var a = 3
  console.log(a)

  fun1()
}
fun2()

当然,js 有个特殊之处,就是 this,思考这段代码:

this.a =  2

function fun1() {
  console.log(this.a) // 1
}

function fun2() {
  this.a = 1
  console.log(this.a) // 1

  fun1()
}
fun2()

是不是疑惑了,说好的从定义的地方向上查找呢,为什么会打印出执行的作用域的值?

这里可以先说答案:因为 this

this.a =  2
// this 指向 window

function fun1() {
  // 这里 this 还是指向 window
  console.log(this) // window
  console.log(this.a) // 1
}

function fun2() {
  // this 依旧指向 window,不信可以打印看看那
  console.log(this.a) // 2

  // 这里修改了外边的 this.a
  this.a = 1
  // 打印修改后的值
  console.log(this.a) // 1

  fun1()
}
fun2()

所以明白了吧? 作用域依旧是在定义的地方向上查找,只不过是两个函数都指向了同一个 this 而已。

这里插一嘴,虽然我认为 js 的 this 是一个设计的非常糟糕的东西(他完全不符合正常人的思维逻辑),我也非常非常久都不再使用 this,但是我认为这个东西还是必须得理解的,不然早晚会搞出大麻烦,你可以不用,但是你必须要懂。

Ok, 接着上面所说,为什么两个函数指向了同一个 this(window)?这里就要深入的了解一下 this 的指向问题:this 究竟指向哪里,是都指向 window 么?显然不是,看一下代码:

this.n = 1

function fun2() {
  console.log(this.n) // 2
}
var a = {
  n: 2,
  fun1() {
    console.log(this) // {n: 2, fun1: function}
    console.log(this.n) // 2
    a.fun2()
  },
  fun2
}

a.fun1()

这里的 fun1 的 this 明显指向了 a 本身,并不是 this,同样 fun2 虽然定义在外部,但是也依然指向了 a ,是不是和之前想的不太一样?fun2 定义在外边,那么他的 this 应该是 window 才对,打印的应该是 1 才对啊,可能这个时候你就在想了,是不是 this 就是动态作用域呢?并不! This 依旧是静态作用域,参考这个代码:

this.n = 1

function fun2() {
  console.log(this.n) // 1
}
var a = {
  n: 2,
  fun1() {
    fun2()
  },
  fun2
}

a.fun1()

发现区别了吗?this 依旧是指向 window,这就说明 this 只是在定义的时候强行绑定了执行他的环境,所以我们通过 a.fun2 调用,this 就指向 a,通过直接调用 fun2(实际等于 window.fun2),指向的则是 window

当然也有例外,比如箭头函数:

this.n = 1

const fun2 = () =>  {
  console.log(this.n)
}
var a = {
  n: 2,
  fun1() {
    // console.log(this)  // {n: 2, fun1: function}
    // console.log(this.n) // 2
    a.fun2()
    // fun2()
  },
  fun2
}

a.fun1()

箭头函数中,不管你是 a.fun2 还是直接 fun2,指向的都是window,因为箭头函数的 this 固定指向他的父作用域,而根据静态作用域的原则,他父作用域是定义时的作用域,也就是 window,所以不管怎么调用,他都是 window。通过以下这个例子更能看出来这一点,箭头函数的 this 固定指向他定义的作用域:

var n = 1
var a = () => {
    console.log(this.n)
}

var b={
    n: 2,
    fun2: {
        n: 3,
        fun1:a,
        fun() {
            a() // 1
            console.log(this) // {n: 3,     fun1:function, fun: function}
            console.log(this.n) // 3
            this.fun1() // 1

        }
    }
}
b.fun2.fun()

通过这个你就能发现,箭头函数的 this 并不指向调用他的对象,也不是指向调用他的对象的父作用域,而是指向他定义的位置的父作用域,不管你在哪里调用,都是同一个指向。

总结

总结一下,对于this,你只需要记住这几点:

  • 正常情况下 this 指向调用他的上下文
  • 箭头函数的 this 指向他的父作用域的 this(静态作用域、静态作用域、静态作用域)
  • new 会创建一个新的对象,this 指向这个对象,详情可以自行了解 new
  • callbindapply 会改变 this 的指向,详情自行了解
a.xx()
xx 内的 this 就是 a
a.b.xx()
xx 内的 this 就是 b

.xxx,. 之前的上下文就是他的 this。 而在非严格模式的全局环境中(严格模式会报错),实际我们定义的变量都是挂载在 window 下,所以 this 指向的是 window

到此这篇关于js词法作用域与this的文章就介绍到这了,更多相关js词法作用域与this内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: js词法作用域与this实例详解

本文链接: https://lsjlt.com/news/166795.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • js词法作用域与this实例详解
    目录前言实践总结前言 静态作用域又叫做词法作用域,采用词法作用域的变量叫词法变量。词法变量有一个在编译时静态确定的作用域。词法变量的作用域可以是一个函数或一段代码,该变量在这段代码区...
    99+
    2024-04-02
  • JS作用域作用链及this使用原理详解
    目录变量提升的原理:JavaScript的执行顺序第一部分:变量提升部分的代码第二部分:代码执行部分代码执行阶段调用栈:栈溢出的原理如何利用调用栈1.使用浏览器查看调用栈的信息2.小...
    99+
    2022-11-13
    JS作用域作用链this JS作用域作用链
  • js中的this作用域全解析
    目录this作用域问题函数式调用方法调用模式在数组中的特例构造器调用模式call、apply、bind特殊情况——箭头函数综合例题this作用域问题 一般来说...
    99+
    2022-11-13
    js中this this作用域 js this作用域
  • Python作用域用法实例详解
    本文实例分析了Python作用域用法。分享给大家供大家参考,具体如下: 每一个编程语言都有变量的作用域的概念,Python也不例外,以下是Python作用域的代码演示: def scope_test()...
    99+
    2022-06-04
    详解 实例 作用
  • Java 中This用法的实例详解
     Java 中This用法的实例详解用类名定义一个变量的时候,定义的只是一个引用,外面可以通过这个引用来访问这个类里面的属性和方法。    那们类里面是够也应该有一个引用来访问自己的属性和方法纳?&n...
    99+
    2023-05-31
    java this ava
  • js中Object.create实例用法详解
    1、用Object.create()方法创建新对象,并使用现有对象提供新对象的proto。 2、提供两个参数,第一个是新创建的原型对象,第二个是为新创建的对象添加属性的对象。 实例 ...
    99+
    2024-04-02
  • JS中fetch()用法实例详解
    目录了解fetch没有fetch时我们获取异步资源的方式:使用fetch后我们获取异步资源的方式fetch的语法fetch的Response对象1.同步属性2.判断请求是否成功发出3...
    99+
    2024-04-02
  • 实例详解JavaScript静态作用域和动态作用域
    目录前言 静态作用域与动态作用域 静态作用域执行过程 动态作用域执行过程 习题 习题一 习题二 习题三 总结 前言 在文章最开始,先学习几个概念: 作用域:《你不知道的j...
    99+
    2024-04-02
  • js数组forEach实例用法详解
    1、forEach()类似于map(),它还将每个元素依次作用于传入函数,但不会返回新的数组。 2、forEach()常用于遍历数组,用于调用数组的每一个元素,并将其传递给回调函数。...
    99+
    2024-04-02
  • mysql中关键词exists的用法实例详解
    目录前言语法解释语法说明使用案例环境准备常用查询exists与in的效率比较循环嵌套查询执行原理循环优化策略exists和in查询原理的区别结论总结前言 在日常开发中,用mysql进...
    99+
    2024-04-02
  • JS中的执行上下文、词法环境和词法作用域都是什么意思
    在JavaScript中,理解执行上下文(Execution Context)、词法环境(Lexical Environment)和词法作用域(Lexical Scope)是非常重要的。1、执行上下文:是JavaScript代码运行时的环境...
    99+
    2023-10-29
    词法 都是 上下文
  • Java关键字this与super详解用法
    目录一、this 关键字的使用1. 概述2. 作用3. 使用3.1 修饰属性和方法3.2 调用构造器3.3 返回当前对象二、super关键字的使用1. 概述2. 使用3. 使用3.1...
    99+
    2024-04-02
  • js中作用域和作用域链及预解析的示例分析
    小编给大家分享一下js中作用域和作用域链及预解析的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!变量---->局部...
    99+
    2024-04-02
  • Android中webview与JS交互、互调方法实例详解
    Android中webview与JS交互、互调方法实例详解 前言: 对于试水的功能,一般公司都会采用H5的方式来开发,可以用很少的资源与很短的项目工期来完成。 但许多情况下,...
    99+
    2022-06-06
    方法 webview js Android
  • vue项目中的this.$get,this.$post等$的用法案例详解
    vue官网上有这么一句话 vue.js的插件应该暴露一个install方法。这个方法的第一个参数是vue构造器,第二个参数是一个可选的选项对象: 注意要首先安装axios 即 np...
    99+
    2022-12-10
    vue 中的this.$get this.$post等$的用法 vue 中this.$get this.$post
  • js中hasOwnProperty的属性及实例用法详解
    1、js不会保护hasOwnProperty被非法占用,如果一个对象碰巧存在这个属性, 就需要使用外部的hasOwnProperty 函数来获取正确的结果。 2、当检查对象上某个属性...
    99+
    2024-04-02
  • Python包中__init__.py文件的作用与用法实例详解
    目录前言一、__init__.py文件简介二、__init__.py文件的使用案例2.1、没有__init__.py文件的目录,使用import xx.xx会报错吗?2.2、在__i...
    99+
    2024-04-02
  • java中构造方法及this关键字的用法实例详解(超详细)
    目录初识构造方法 构造方法的使用 初识this this.xx的用法this()用于构造函数的调用总结初识构造方法  我们上篇讲了java中类...
    99+
    2024-04-02
  • ajax在js中和jQuery中的用法实例详解
    目录原生 JS 怎么发送一个 get 请求怎么发送一个 post 请求发送一个带有参数的 get 请求发送一个带有参数的 post 请求jQuery $.get 几个参数,怎么使用$...
    99+
    2024-04-02
  • Android与JS之间跨平台异步调用实例详解
    Android与JS之间跨平台异步调用  为什么突然要搞这个问题呢?    在开发浏览器的时候遇到这个狗血的问题,花了将近1天的时间才想到这个解决方案,Androi...
    99+
    2022-06-06
    调用 异步 异步调用 跨平台 js Android
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作