实例详解JavaScript静态作用域和动态作用域

目录
  • 前言
  • 静态作用域与动态作用域
    • 静态作用域执行过程
    • 动态作用域执行过程
  • 习题
    • 习题一
    • 习题二
    • 习题三
  • 总结

前言

在文章最开始,先学习几个概念:

  • 作用域:《你不知道的js》中指出,作用域是一套规则,这套规则用来管理引擎如何在当前作用域以及嵌套的子作用域中根据标识符名称进行变量查找。简单来说,作用域规定了如何查找变量。
  • 静态作用域:又称词法作用域,函数的作用域在函数定义的时候就决定了,通俗点说就是你在写代码时将变量和块作用域写在哪里决定的。
  • 动态作用域:函数的作用域在函数调用时才决定的。

静态作用域与动态作用域

JavaScript采用的是静态作用域,函数定义的位置就决定了函数的作用域。

具体看一个例子,理解一下什么是静态作用域与动态作用域的区别

var val = 1;
function test() {
    console.log(val);
}
function bar() {
    var val = 2;
    test();
}

bar();
// 结果是???

上面代码中:

  • 我们首先定义全局变量 val,赋值为 1
  • 声明一个函数 text,函数的功能是打印 val 这个变量的值
  • 声明一个函数 bar,函数内部定义局部变量 val,赋值为 2;并且函数内部执行 test() 函数
  • 执行 bar() 函数

静态作用域执行过程

当执行 test 函数时,先从 test 函数内部查找是否有变量 val,如果没有,就沿定义函数的位置,查找上一层的代码,查找到全局变量 val ,其值为 1。

作用域查找始终从运行时所处的最内层作用域开始查找,逐级向外查找,直到遇见第一个匹配的标识符为止。

无论函数在哪里被调用,无论如何被调用,它的作用域只由函数定义所处的位置决定。

动态作用域执行过程

执行 test 函数,首先从函数内部查询 val 变量,如果没有,就从调用函数的作用域,即 bar 函数的作用域内部查找变量 val,所以打印结果 2

习题

我们来看三个习题,好好消化理解一下静态作用域: 函数定义位置就决定了作用域。

习题一

var a = 1
function fn1(){
    function fn3(){
        var a = 4
        fn2()
    }
    var a = 2
    return fn3
}
function fn2(){
    console.log(a)
}
var fn = fn1()
fn()

上面代码中:

  • 我们首先定义全局变量 a,赋值为 1
  • 声明一个函数 fn1,函数的内部分别声明了函数 fn3,定义局部变量 a,赋值为 2,返回值为 fn3 函数
  • fn3 函数内部定义局部变量 a,赋值为 4,执行 fn2()
  • 声明函数 fn2, 函数的功能是,打印 a 的值
  • fn 赋值为 fn1() 的返回值
  • 执行 fn() (相当于执行 fn3 函数)

做题之前,一定要理解 静态作用域 的概念。该题 fn2 定义在全局上,当 fn2 中找不到变量 a 时,它会去全局中寻找,与 fn1 和 fn3 毫无关系,打印 1.

习题二

var a = 1
function fn1(){
    function fn2(){
        console.log(a)
    }
    function fn3(){
        var a = 4
        fn2()
    }
    var a = 2
    return fn3
}
var fn = fn1()
fn()

fn2 是定义在函数 fn1 内部,因此当 fn2 内部没有变量 a 时,它会去 fn1 中寻找,跟函数 fn3 毫无关系,如果 fn1 中寻找不到,会到 fn1 定义的位置的上一层(全局)寻找,直至寻找到第一个匹配的标识符。本题可以在 fn1 中找到变量 a,打印 2

习题三

var a = 1;
function fn1(){
    function fn3(){
        function fn2(){
            console.log(a)
        }
        var a;
        fn2()
        a = 4
    }
    var a = 2
    return fn3
}
var fn = fn1()
fn()

该题 fn2 定义在函数 fn3 中,当 fn2 中找不到变量 a 时,会首先去 fn3 中查找,如果还查找不到,会到 fn1 中查找。本题可以在 fn3 中找到变量 a,但由于 fn2() 执行时,a 未赋值,打印 undefined。

总结

关于JavaScript 的静态作用域,我们只需要记住一句话:函数定义的位置就决定了函数的作用域,遇到题目时不要被别的代码干扰到。

到此这篇关于JavaScript静态作用域和动态作用域的文章就介绍到这了,更多相关JS静态作用域和动态作用域内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 图解JavaScript作用域链底层原理

    目录 前言 作用域 1.什么是作用域 2.[[Scopes]]属性 3.作用域链 4.图解查找变量原理 总结 前言 在学习JavaScript时大家一定都知道,外部空间不能访问内部变量,我们往往只知道这一基本规则,那实现这一基本规则的基本底层原理是什么呢?今天我将从小白的角度来带大家理解作用域链,希望能给大家一些帮助! 作用域 1.什么是作用域 简单来说,作用域(英文:scope)是据名称来查找变量的一套规则,可以把作用域通俗理解为一个封闭的空间,这个空间是封闭的,不会对外部产生影响,外部空间不

  • JavaScript ES新特性块级作用域

    目录 1.块级作用域是什么 2.为什么需要块级作用域 3.与函数声明 前言: 在学习块级作用域之前需要我们对作用域有个了解,所谓的作用域就是代码当中的某个成员起作用的范围. 1.块级作用域是什么 所谓的块级作用域,就是该变量只能在声明时的代码块或者子代码块中使用.在ECMAScript 2015以前的版本中是不存在块级作用域的,而ECMAScript 2015提供的let关键字,使JavaScript出现了块级作用域,示例代码如下所示 /* * 块级作用域只能使用 let 关键字 * let关键

  • JavaScript高级程序设计之变量与作用域

    目录 1.原始值与引用值 2.instanceof 3.作用域 1.原始值与引用值 6种简单数据类型的值都是原始值, 原始值通过变量赋值给另一个变量时,会复制一个出一个新的值,两者相互独立. let num1 = 5 let num2 = num1 引用值通过变量赋值给另一个变量时,也会复制一个值,这个值其实是一个指针(引用),该指针指向的还是同一个对象. let obj1 = new Object() let obj2 = obj1 既然是指向同一个引用对象,那么给obj1添加属性,也会作用到

  • JavaScript基础之作用域

    目录 作用域 全局作用域 函数作用域 if,switch,for ,while 块作用域 作用域链 总结 再聊AO和BO之前还需要了解作用域的概念,这样方便后面了解很多东西,比如this指向等. 作用域 作用域(Scope)简单的说就是变量,函数和对象定义后其可用的范围. console.log(a) { var a=1; } function test(){ var b=2; } 可以看出在外面无法使用变量b.可以看出作用域可以保护数据不会被外部随意访问,以及修改.简单可以看出作用域可以相互隔

  • Javascript作用域与闭包详情

    目录 1.作用域 2.作用域链 3.词法作用域 5.闭包的应用 6.闭包的缺陷 7.高频闭包面试题 1.作用域 简单来说,作用域是指程序中定义变量的区域,它决定了当前执行代码对变量的访问权限 在ES5中,一般只有两种作用域类型: 全局作用域:全局作用域作为程序的最外层作用域,一直存在 函数作用域:函数作用域只有在函数被定义时才会被创建,包含在父级函数作用域或全局作用域中 说完概念,我们来看下面这段代码: var a = 100 function test(){ var b = a * 2 var

  • JS难点同步异步和作用域与闭包及原型和原型链详解

    目录 JS三座大山 同步异步 同步异步区别 作用域.闭包 函数作用域链 块作用域 闭包 闭包解决用var导致下标错误的问题 投票机 闭包两个面试题 原型.原型链 原型对象 原型链 完整原型链图 JS三座大山 同步异步 前端中只有两个操作是异步的: 定时器异步执行; ajax异步请求 编译器解析+执行代码原理: 1.编译器从上往下逐一解析代码 2.判断代码是同步还是异步 同步:立即执行 异步:不执行.放入事件队列池 3.等所有同步执行完毕开始执行异步 同步异步区别 api : 异步有回调,同步没有

  • 浅谈JavaScript作用域

    目录 一.作用域 1.全局作用域 2.局部作用域 二.变量的作用域 1.全局变量 2.局部变量 3.全局变量和局部变量的区别 三.作用域链 一.作用域 通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域.作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突. JavaScript(es6前)中的作用域有两种: 全局作用域 局部作用域(函数作用域) 在ES6后,还有一个块级作用域,以后在详述. 1.全局作用域 作用于所有

  • 实例详解JavaScript静态作用域和动态作用域

    目录 前言 静态作用域与动态作用域 静态作用域执行过程 动态作用域执行过程 习题 习题一 习题二 习题三 总结 前言 在文章最开始,先学习几个概念: 作用域:<你不知道的js>中指出,作用域是一套规则,这套规则用来管理引擎如何在当前作用域以及嵌套的子作用域中根据标识符名称进行变量查找.简单来说,作用域规定了如何查找变量. 静态作用域:又称词法作用域,函数的作用域在函数定义的时候就决定了,通俗点说就是你在写代码时将变量和块作用域写在哪里决定的. 动态作用域:函数的作用域在函数调用时才决定的. 静

  • Java代理模式实例详解【静态代理与动态代理】

    本文实例讲述了Java代理模式.分享给大家供大家参考,具体如下: 即Proxy Pattern,23种java常用设计模式之一.代理模式的定义:对其他对象提供一种代理以控制对这个对象的访问. Java的代理模式是Java中比较常用的设计模式,分为2中代理:静态代理与动态代理(JDK动态代理和cglib动态代理) 优点: 职责清晰 真实角色只需关注业务逻辑的实现,非业务逻辑部分,后期通过代理类完成即可. 高扩展性 不管真实角色如何变化,由于接口是固定的,代理类无需做任何改动. 缺点: 很明显的一点

  • JavaScript事件概念详解(区分静态注册和动态注册)

    js中的事件 什么是事件?事件是电脑输入设备与页面进行交互的响应,我们称之为事件 事件类型 鼠标单击:例如单击button.选中checkbox和radio等元素:鼠标进入.悬浮或退出页面的某个热点:例如鼠标停在一个图片上方或者进入table的范围: 键盘按键:当按下按键或释放按键时: HTML事件:例如页面body被加载时:在表单中选取输入框或改变输入框中文本的内容:例如选中或修改了文本框中的内容: 突变事件:主要指文档底层元素发生改变时触发的事件,如DomSubtreeModified(DO

  • js对象实例详解(JavaScript对象深度剖析,深度理解js对象)

    这算是酝酿很久的一篇文章了. JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕. 平时发的文章基本都是开发中遇到的问题和对最佳解决方案的探讨,终于忍不住要写一篇基础概念类的文章了. 本文探讨以下问题,在座的朋友各取所需,欢迎批评指正: 1.创建对象 2.__proto__与prototype 3.继承与原型链 4.对象的深度克隆 5.一些Object的方法与需要注意的点 6.ES6新增特性 下面反复提到实例对象和原型对象,通过构造函数 new

  • xcode 详解创建静态库和动态库的方法

    xcode 创建静态库和动态库 1.linux中静态库和动态库区别: 库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行.库分静态库和动态库两种. 静态库:这类库的名字一般是libxxx.a:利用静态函数库编译成的文件比较大,因为整个函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了.当然这也会成为他的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译. 动态库:这类库的名字一般是lib

  • 实例详解JavaScript获取链接参数的方法

    使用url传递参数,大家应该不陌生,例如: http://www.softwhy.com/home.php?mod=space&do=home&view=all 既然传递参数,那么自然就要获得传递的参数,当然获取参数的方式有多种多样,下面就介绍其中的一种,和大家一起分享,希望能够给大家带来一定的帮助,代码如下: var url="http://www.softwhy.com/home.php?mod=space&do=home&view=all"; if

  • 实例详解JavaScript中setTimeout函数的执行顺序

    前言 setTimeout,前端工程师必定会打交道的一个函数.它看上去非常的简单,朴实,有着一个很不平凡的名字--定时器.其实网上关于JavaScript中setTimeout的文章很多,但总感觉例子不够直接具体,因此写了个简单的例子并加以解释希望能让大家明白setTimeout是如何执行的.下面话不多说了,来一起看看详细的介绍: 实例代码如下: var time1=new Date().getTime(); console.log(1,time1); setTimeout(function()

  • 图文详解Javascript中的上下文和作用域

    执行上下文(Execution context) 执行上下文(简称上下文)决定了Js执行过程中可以获取哪些变量.函数.数据,一段程序可能被分割成许多不同的上下文,每一个上下文都会绑定一个变量对象(variable object),它就像一个容器,用来存储当前上下文中所有已定义或可获取的变量.函数等.位于最顶端或最外层的上下文称为全局上下文(global context),全局上下文取决于执行环境,如Node中的global和Browser中的window: 需要注意的是,上下文与作用域(scop

  • JavaScript设计模式之调停者模式实例详解

    本文实例讲述了JavaScript设计模式之调停者模式.分享给大家供大家参考,具体如下: 1.定义 调停者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用.从而使他们可以松散偶合.当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用.保证这些作用可以彼此独立的变化.调停者模式将多对多的相互作用转化为一对多的相互作用.调停者模式将对象的行为和协作抽象化,把对象在小尺度的行为上与其他对象的相互作用分开处理. 2.使用的原因 当对象之间的交互操作很多,且每个对象的行为操

  • 详解Vue 匿名、具名和作用域插槽的使用方法

    Vue 中的插槽在开发组件的过程中其实是非常重要并且好用的.Vue 的插槽也没有说很难使用,这篇文章简明扼要的介绍了三种插槽的用法. 匿名插槽 子组件定义 slot 插槽,但并未具名,因此也可以说是默认插槽.只要在父元素中插入的内容,默认加入到这个插槽中去.

随机推荐