作用域_作用域链 - CSDN
作用域 订阅
作用域(scope),程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强程序的可靠性,减少名字冲突。对于对象而言(其他也是一样的),在main函数中,对象的作用域为他所在的最近的一对花括号内。在后花括号处析构函数被调用;全局的对象的作用域为声明之后的整个文件,析构函数在最后被调用。另外,临时产生的对象在使用完后立即会被析构。 展开全文
作用域(scope),程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强程序的可靠性,减少名字冲突。对于对象而言(其他也是一样的),在main函数中,对象的作用域为他所在的最近的一对花括号内。在后花括号处析构函数被调用;全局的对象的作用域为声明之后的整个文件,析构函数在最后被调用。另外,临时产生的对象在使用完后立即会被析构。
信息
外文名
scope
属    于
程序设计语言中非常重要
中文名
作用域
目    的
减少名字冲突
作用域程序设计概念
作用域(scope)作用域在许多程序设计语言中非常重要。通常来说,一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强程序的可靠性,减少名字冲突。对于对象而言(其他也是一样的),在main函数中,对象的作用域为他所在的最近的一对花括号内。在后花括号处析构函数被调用;全局的对象的作用域为声明之后的整个文件,析构函数在最后被调用。另外,临时产生的对象在使用完后立即会被析构。下面是一个简单的例子。#include using namespace std;class X {public:X() {cout << "X::X()\n";}~X() {cout << "X::~X()\n";}};X f1(X x1) //完全不使用引用{cout << "f1(X f)\n";return x1;}X& f2(X& x2) //完全使用引用{cout << "f2(X f)\n";return x2;}X Globle_X; //全局版本int main(){cout << "--------\n";{X Local_X; //局部版本cout << "--------\n";}cout << "--------\n";X Normal_X;f1(Normal_X);cout << "--------\n";f2(Normal_X);cout << "--------\n";}程序执行结果为:X::X()--------X::X()--------X::~X()--------X::X()f1(X f)X::~X()X::~X()--------f2(X f)--------X::~X()大家对照着就能看出来了……
收起全文
精华内容
参与话题
  • 作用域是什么

    千次阅读 2018-10-26 20:03:50
    1.编译原理  传统的编译语言的流程中,程序的一段源代码在执行之前会经历三个步骤: 分词/词法分析(Tokenizing/Lexing)  将由字符组成的字符串分解成有意义的代码块,这些代码块被称为词法单元。...

    1.编译原理

         传统的编译语言的流程中,程序的一段源代码在执行之前会经历三个步骤:

    • 分词/词法分析(Tokenizing/Lexing)

            将由字符组成的字符串分解成有意义的代码块,这些代码块被称为词法单元。

    • 解析/语法分析

            将词法单元流转换成一个由元素逐级嵌套所组成代表了程序语法结构的树(抽象语法树)

    • 代码生成

            将抽象语法树转换为可执行的过程。

    2.理解作用域

        1.参与处理代码的部件:

    • 引擎:从头到尾负责程序的额编译及执行过程
    • 编译器:负责语法分析及代码生成
    • 作用域:负责收集并维护所有声明的标识符组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限。

        2.变量的赋值操作执行两个动作:

    • 编译器在当前作用域声明一个变量
    • 然后在运行时引擎会在作用域中查找该变量。如果能够找到就给对它赋值

        3.LHS查询和RHS查询

           变量出现在赋值操作的左侧进行LHS查询:试图找到变量的容器本身,从而可以对其赋值(即赋值操作的目标是谁)

           变量出现在赋值操作的右侧进行RHS查询:简单地查找某个变量的值(即谁是赋值操作的源头)

           (注意:参数传递实际为一种隐式的赋值操作)

    3.作用域嵌套

        当一个块或函数嵌套在另一个块或函数中,就发生了作用域的嵌套。

         因此,在当前作用域中找不到某个变量时,引擎就会在外层嵌套的作用域中继续查找,直到找到该变量或抵达最外层的作用域为止。

         LHS和RHS引用都会在当前楼层进行查找,如果没有找到,就会坐电梯上前往上一层楼。如果还是没有找到,以此类推。一旦抵达顶层,可能找到了也可能没找到,无论如何查找过程都将会停止。

    4.异常

         1.在变量尚未声明时,LHS和RHS查询的行为是不一样的。

    • 如果RHS查询在所有嵌套的作用域都遍寻不到所需的变量,引擎将会抛出ReferenceError异常
    • 如果LHS查询在全局作用域也无法找到目标变量,全局作用域就会创建一个具有该名称的变量,将其归还给引擎。(前提:程序运行在非严格模式)
    • 如果RHS查询到了一个变量,但是尝试对这个变量的值进行不合理的操作,引擎就会抛出一种类型的异常,叫做TypeError。

        2.区分ReferenceError和TypeError

    • ReferenceError:同作用域判别失败有关
    • TypeError:表示作用域判别成功了,对是对结果的操作是非法或不合理的。

        3.关于严格模式

           严格模式一个不同的行为是:禁止自动或隐式地创建全局变量。

     

     

    展开全文
  • 深入理解JavaScript作用域作用域

    万次阅读 2019-04-06 22:02:36
    虽然对于许多新手开发者来说,作用域的概念并不是很容易理解,本文我会尽我所能用最简单的方式来解释作用域作用域链,希望大家有所收获! 作用域(Scope) 1.什么是作用域 作用域是在运行时代码中的某些特定部分...

    前言

    JavaScript中有一个被称为作用域(Scope)的特性。虽然对于许多新手开发者来说,作用域的概念并不是很容易理解,本文我会尽我所能用最简单的方式来解释作用域和作用域链,希望大家有所收获!

    想阅读更多优质文章请猛戳GitHub博客,一年五十篇优质文章等着你!

    作用域(Scope)

    1.什么是作用域

    作用域是在运行时代码中的某些特定部分中变量,函数和对象的可访问性。换句话说,作用域决定了代码区块中变量和其他资源的可见性。可能这两句话并不好理解,我们先来看个例子:

    function outFun2() {
        var inVariable = "内层变量2";
    }
    outFun2();//要先执行这个函数,否则根本不知道里面是啥
    console.log(inVariable); // Uncaught ReferenceError: inVariable is not defined
    

    从上面的例子可以体会到作用域的概念,变量inVariable在全局作用域没有声明,所以在全局作用域下取值会报错。我们可以这样理解:作用域就是一个独立的地盘,让变量不会外泄、暴露出去。也就是说作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。

    ES6 之前 JavaScript 没有块级作用域,只有全局作用域和函数作用域。ES6的到来,为我们提供了‘块级作用域’,可通过新增命令let和const来体现。

    2.全局作用域和函数作用域

    在代码中任何地方都能访问到的对象拥有全局作用域,一般来说以下几种情形拥有全局作用域:

    • 最外层函数 和在最外层函数外面定义的变量拥有全局作用域
    var outVariable = "我是最外层变量"; //最外层变量
    function outFun() { //最外层函数
        var inVariable = "内层变量";
        function innerFun() { //内层函数
            console.log(inVariable);
        }
        innerFun();
    }
    console.log(outVariable); //我是最外层变量
    outFun(); //内层变量
    console.log(inVariable); //inVariable is not defined
    innerFun(); //innerFun is not defined
    
    • 所有末定义直接赋值的变量自动声明为拥有全局作用域
    function outFun2() {
        variable = "未定义直接赋值的变量";
        var inVariable2 = "内层变量2";
    }
    outFun2();//要先执行这个函数,否则根本不知道里面是啥
    console.log(variable); //未定义直接赋值的变量
    console.log(inVariable2); //inVariable2 is not defined
    
    • 所有window对象的属性拥有全局作用域

    一般情况下,window对象的内置属性都拥有全局作用域,例如window.name、window.location、window.top等等。

    全局作用域有个弊端:如果我们写了很多行 JS 代码,变量定义都没有用函数包括,那么它们就全部都在全局作用域中。这样就会 污染全局命名空间, 容易引起命名冲突。

    // 张三写的代码中
    var data = {a: 100}
    
    // 李四写的代码中
    var data = {x: true}
    

    这就是为何 jQuery、Zepto 等库的源码,所有的代码都会放在(function(){....})()中。因为放在里面的所有变量,都不会被外泄和暴露,不会污染到外面,不会对其他的库或者 JS 脚本造成影响。这是函数作用域的一个体现。

    函数作用域,是指声明在函数内部的变量,和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,最常见的例如函数内部。

    function doSomething(){
        var blogName="浪里行舟";
        function innerSay(){
            alert(blogName);
        }
        innerSay();
    }
    alert(blogName); //脚本错误
    innerSay(); //脚本错误
    

    作用域是分层的,内层作用域可以访问外层作用域的变量,反之则不行。我们看个例子,用泡泡来比喻作用域可能好理解一点:

    最后输出的结果为 2, 4, 12

    • 泡泡1是全局作用域,有标识符foo;
    • 泡泡2是作用域foo,有标识符a,bar,b;
    • 泡泡3是作用域bar,仅有标识符c。

    值得注意的是:块语句(大括号“{}”中间的语句),如 if 和 switch 条件语句或 for 和 while 循环语句,不像函数,它们不会创建一个新的作用域。在块语句中定义的变量将保留在它们已经存在的作用域中。

    if (true) {
        // 'if' 条件语句块不会创建一个新的作用域
        var name = 'Hammad'; // name 依然在全局作用域中
    }
    console.log(name); // logs 'Hammad'
    

    JS 的初学者经常需要花点时间才能习惯变量提升,而如果不理解这种特有行为,就可能导致
    bug 。正因为如此, ES6 引入了块级作用域,让变量的生命周期更加可控。

    3.块级作用域

    块级作用域可通过新增命令let和const声明,所声明的变量在指定块的作用域外无法被访问。块级作用域在如下情况被创建:

    1. 在一个函数内部
    2. 在一个代码块(由一对花括号包裹)内部

    let 声明的语法与 var 的语法一致。你基本上可以用 let 来代替 var 进行变量声明,但会将变量的作用域限制在当前代码块中。块级作用域有以下几个特点:

    • 声明变量不会提升到代码块顶部

    let/const 声明并不会被提升到当前代码块的顶部,因此你需要手动将 let/const 声明放置到顶部,以便让变量在整个代码块内部可用。

    function getValue(condition) {
    if (condition) {
    let value = "blue";
    return value;
    } else {
    // value 在此处不可用
    return null;
    }
    // value 在此处不可用
    }
    
    • 禁止重复声明

    如果一个标识符已经在代码块内部被定义,那么在此代码块内使用同一个标识符进行 let 声明就会导致抛出错误。例如:

    var count = 30;
    let count = 40; // Uncaught SyntaxError: Identifier 'count' has already been declared
    

    在本例中, count 变量被声明了两次:一次使用 var ,另一次使用 let 。因为 let 不能在同一作用域内重复声明一个已有标识符,此处的 let 声明就会抛出错误。但如果在嵌套的作用域内使用 let 声明一个同名的新变量,则不会抛出错误。

    var count = 30;
    // 不会抛出错误
    if (condition) {
    let count = 40;
    // 其他代码
    }
    
    • 循环中的绑定块作用域的妙用

    开发者可能最希望实现for循环的块级作用域了,因为可以把声明的计数器变量限制在循环内,例如:

    for (let i = 0; i < 10; i++) {
      // ...
    }
    console.log(i);
    // ReferenceError: i is not defined
    

    上面代码中,计数器i只在for循环体内有效,在循环体外引用就会报错。

    var a = [];
    for (var i = 0; i < 10; i++) {
      a[i] = function () {
        console.log(i);
      };
    }
    a[6](); // 10
    

    上面代码中,变量i是var命令声明的,在全局范围内都有效,所以全局只有一个变量i。每一次循环,变量i的值都会发生改变,而循环内被赋给数组a的函数内部的console.log(i),里面的i指向的就是全局的i。也就是说,所有数组a的成员里面的i,指向的都是同一个i,导致运行时输出的是最后一轮的i的值,也就是 10。

    如果使用let,声明的变量仅在块级作用域内有效,最后输出的是 6。

    var a = [];
    for (let i = 0; i < 10; i++) {
      a[i] = function () {
        console.log(i);
      };
    }
    a[6](); // 6
    

    上面代码中,变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。

    另外,for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。

    for (let i = 0; i < 3; i++) {
      let i = 'abc';
      console.log(i);
    }
    // abc
    // abc
    // abc
    

    上面代码正确运行,输出了 3 次abc。这表明函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域。

    作用域链

    1.什么是自由变量

    首先认识一下什么叫做 自由变量 。如下代码中,console.log(a)要得到a变量,但是在当前的作用域中没有定义a(可对比一下b)。当前作用域没有定义的变量,这成为 自由变量 。自由变量的值如何得到 —— 向父级作用域寻找(注意:这种说法并不严谨,下文会重点解释)。

    var a = 100
    function fn() {
        var b = 200
        console.log(a) // 这里的a在这里就是一个自由变量
        console.log(b)
    }
    fn()
    

    2.什么是作用域链

    如果父级也没呢?再一层一层向上寻找,直到找到全局作用域还是没找到,就宣布放弃。这种一层一层的关系,就是 作用域链 。

    var a = 100
    function F1() {
        var b = 200
        function F2() {
            var c = 300
            console.log(a) // 自由变量,顺作用域链向父作用域找
            console.log(b) // 自由变量,顺作用域链向父作用域找
            console.log(c) // 本作用域的变量
        }
        F2()
    }
    F1()
    

    3.关于自由变量的取值

    关于自由变量的值,上文提到要到父作用域中取,其实有时候这种解释会产生歧义。

    var x = 10
    function fn() {
      console.log(x)
    }
    function show(f) {
      var x = 20
      (function() {
        f() //10,而不是20
      })()
    }
    show(fn)
    

    在fn函数中,取自由变量x的值时,要到哪个作用域中取?——要到创建fn函数的那个作用域中取,无论fn函数将在哪里调用

    所以,不要在用以上说法了。相比而言,用这句话描述会更加贴切:要到创建这个函数的那个域”。
    作用域中取值,这里强调的是“创建”,而不是“调用”
    ,切记切记——其实这就是所谓的"静态作用域"

    var a = 10
    function fn() {
      var b = 20
      function bar() {
        console.log(a + b) //30
      }
      return bar
    }
    var x = fn(),
      b = 200
    x() //bar()
    

    fn()返回的是bar函数,赋值给x。执行x(),即执行bar函数代码。取b的值时,直接在fn作用域取出。取a的值时,试图在fn作用域取,但是取不到,只能转向创建fn的那个作用域中去查找,结果找到了,所以最后的结果是30

    作用域与执行上下文

    许多开发人员经常混淆作用域和执行上下文的概念,误认为它们是相同的概念,但事实并非如此。

    我们知道JavaScript属于解释型语言,JavaScript的执行分为:解释和执行两个阶段,这两个阶段所做的事并不一样:

    解释阶段:

    • 词法分析
    • 语法分析
    • 作用域规则确定

    执行阶段:

    • 创建执行上下文
    • 执行函数代码
    • 垃圾回收

    JavaScript解释阶段便会确定作用域规则,因此作用域在函数定义时就已经确定了,而不是在函数调用时确定,但是执行上下文是函数执行之前创建的。执行上下文最明显的就是this的指向是执行时确定的。而作用域访问的变量是编写代码的结构确定的。

    作用域和执行上下文之间最大的区别是:
    执行上下文在运行时确定,随时可能改变;作用域在定义时就确定,并且不会改变

    一个作用域下可能包含若干个上下文环境。有可能从来没有过上下文环境(函数从来就没有被调用过);有可能有过,现在函数被调用完毕后,上下文环境被销毁了;有可能同时存在一个或多个(闭包)。同一个作用域下,不同的调用会产生不同的执行上下文环境,继而产生不同的变量的值

    给大家推荐一个好用的BUG监控工具Fundebug,欢迎免费试用!

    欢迎关注公众号:前端工匠,你的成长我们一起见证!如果你感觉有收获,欢迎给我打赏,以激励我更多输出优质开源内容

    参考文章和书籍

    展开全文
  • 四大作用域

    千次阅读 2018-09-20 20:06:43
    四大作用域: 一、application(ServletContext) 1、生命周期:当Web应用被加载进容器时创建代表整个web应用的application对象,当服务器关闭或Web应用被移除时,application对象跟着销毁。 2、作用范围:整个Web...

    四大作用域:
    一、application(ServletContext)
    1、生命周期:当Web应用被加载进容器时创建代表整个web应用的application对象,当服务器关闭或Web应用被移除时,application对象跟着销毁。  
    2、作用范围:整个Web应用。
    3、作用:   
      a)application.setAttribute(“key”,Object value):存储整个web应用公用的数据
    b)在不同Servlet 之间转发(不常用)    
    this.getServletContext().getRequestDispatcher("/servlet/Demo10Servlet").forward(request,response);   
     方法执行结束,service就会返回到服务器,再有服务器去调用目标servlet,其中request会重新创建,并将之前的request的数据拷贝进去。      
    注意:由于request对象也有getRequestDispatcher("**")方法,所有我们开发是通常使用request调用该方法实现重定向。
    二、session 域 (HttpSession)
      HttpSession 在服务器中,为浏览器创建独一无二的内存空间,在其中保存会话相关的信息。
      1、生命周期:在第一次调用 request.getSession() 方法时,服务器会检查是否已经有对应的session,如果没有就在内存中创建一个session并返回。   
    当一段时间内session没有被使用(默认为30分钟),则服务器会销毁该session。 如果服务器非正常关闭(强行关闭),没有到期的session也会跟着销毁。 如果调用session提
    供的invalidate() ,可以立即销毁session。
      注意:服务器正常关闭,再启动,Session对象会进行钝化和活化操作。同时如果服务器钝化的时间在session 默认销毁时间之内,则活化后session还是存在的。否则Session
    不存在。如果JavaBean 数据在session钝化时,没有实现Serializable 则当Session活化时,会消失。
     2、作用范围:一次会话。  
       3、作用:保存登录的用户信息、购物车信息等
    三、request域  --(HttpServletRequest) 
     1、生命周期:在service 方法调用前由服务器创建,传入service方法。整个请求结束,request生命结束。  
     2、作用范围:整个请求链(请求转发也存在)。  
     3、作用:  在整个请求链中共享数据。最常用到:在Servlet 中处理好的数据交给Jsp显示,此时参数就可以放置在Request域中带过去。
    四、pageContext域—(PageContext)
     1、生命周期:当对JSP的请求时开始,当响应结束时销毁。  
     2、作用范围:整个JSP页面,是四大作用域中最小的一个。  
      作用:   
      (1)获取其它八大隐式对象,可以认为是一个入口对象。   
      (2)获取其所有域中的数据  


    pageContext 当前页的pageContext对象 :
    ${pageContext.request.contextPath}返回的是request.getContextPath()的值,我们经常使用这个来拼接jsp中的绝对路径。
    这里的${pageContext.request.contextPath}是一种特殊用法,不能使用${request.contextPath}的形式替代。
    requestScope 把request作用域中的数据映射为一个map对象
    pageScope, requestScope, sessionScope, appliationScope都可以看作是Map型变量,调用其中的数据可以使用${pageScope.name}或${pageScope["name"]}的形式,这两种写法
    是等价的。
    在有特殊符号时情况下只能使用${pageScope["content-type"]},jsp无法解析连字符(-)会出现错误。
    paramValues request.getParameterValues()
    需要注意的是${paramValues.name}得到的是一个字符串数组,如果需要获得其中某个值,还需要使用${paramValues.name[0]}指定数组中的索引。
    这与${headerValues.name}是相似的。
    header 对应request.getHeader()
    ${header.name}会取得http请求中的header参数,现实工作中很少用到这里的数据。
    cookie 对应request.getCookies()
    所谓的cookie是一个小小的文本文件,它是以key、value的方式将Session Tracking的内容记录在这个文本文件内,这个文本文件通常存在于浏览器的暂存区内。
    JSTL并没有提供设定cookie的动作,因为这个动作通常都是后端开发者必须去做的事情,而不是交给前端的开发者。
    例:
    Cookie cookie = new Cookie("username", "Username in cookie"); response.addCookie(cookie);
    创建一个名称为username,值为"Username in cookie"的Cookie对象,然后发送给客户端然后我们就可以使用${cookie.username}获得这个cookie了,${cookie.username.name}获
    得cookie名称,${cookie.username.value}获得cookie值。
    initParam 对应ServletContext.getInitParamter()
    ServletContext.getInitParamter()指的应用的初始变量,这些变量都是定义在web.xml中的。
    <context-param> <param-name>username</param-name> <param-value>username with context param</param-value> </context-param>
    ${initParam.username}就会得到这里的变量值。

    展开全文
  • JS作用域的理解

    千次阅读 2019-03-21 16:34:52
    JS作用域的理解 理解JS函数的作用域有助于我们分析函数执行,调用。 什么是作用域? JS的函数作用域,将作用域拆开来看,“作用”表示读写操作,函数可以读取代码,改写代码;“域”表示空间,范围,区域。一般指在...

    JS作用域的理解

    理解JS函数的作用域有助于我们分析函数执行,调用。

    什么是作用域?

    JS的函数作用域,将作用域拆开来看,“作用”表示读写操作,函数可以读取代码,改写代码;“域”表示空间,范围,区域。一般指在

    函数作用于的操作流程

    函数在执行的时候,至少会发生这两件事。第一是预解析,第二是逐行解读代码。

    预解析:函数在执行的时候,会读取到整个函数内的关键字或参数。比如var、function、参数。读取过程中并不会读取到等号右边的代码。也就是说当读取到var的时候,其实是一种未定义的状态,读取到function的时候,是将整个函数全部提取; 逐行解读代码:预解析之后,就来逐行解读代码,执行代码;当在逐行解读的时候,如果碰到函数调用,那么就会先解读函数内部的代码块,这个时候就又会遵循函数作用域的执行过程。先解析,再解读。其中就涉及到全局变量和局部变量的操作。 逐行解读代码的一些原则:

    1、逐行解读过程中,当碰到表达式的时候,就会用表达式修改预解析的值;表达式是=、+、-、*、/、参数(注意,参数也是表达式,参数可以被修改)

    2、预解析的时候,遇到重名的变量名称,字母,值留下一个;

    3、预解析时,当变量碰到函数的名称一致的时候,值留下函数块。因为预解析的时候,变量其实是未定义的状态

    4、逐行解读代码时,碰到函数,如果没有调用,表示函数没有执行。此时直接略过,直到有表达式才能改变变量的值。

    5、所有变量,在正式运行代码之前,都会提前赋一个值;未定义。所有函数,在预解析的时候,都是函数块;

    6、逐行解读代码时,是从上到下,从函数内部到函数外部的执行过程

    简单案例:

    <script type="text/javascript">
       alert(a);
      var a=1;//undefined
    </script>
    <script type="text/javascript">
      var a=1;
      alert(a);//弹出1
    </script>
    

    以上这两段代码,只是调换了一下顺序,执行的结果就不相同。分析一下它们的执行过程 第一段代码:1、解析器先找到

    2、然后逐行解读代码,从上到下,先解析了alert的代码,并执行,这个时候a还是属于一种未定义的状态,因此弹出了undefined;

    第二段代码:1、解析器先找到

    2、逐行解读代码。从上到下,var a=1,为a进行了赋值,此时a=1,再解读alert(a)的值,那么最后弹出1.

    复杂的案例:

    alert(a);                
    var a = 1;
    alert(a);                  
    function a (){ alert(2); }
    alert(a);               
    var a=3;     
    alert(a);                   
    function a (){ alert(4); }
    alert(a);
    

    上述这行代码,比较复杂,但我们依然按照作用域的解析过程来分析分析

    1、预解析。找到关键字var和function。 从上到下,依次预解析的值有变化。先是第二行代码,var a是一种未定义;然后是第四行代码,是一个函数,此时函数a的值就覆盖了第二行代码的未定义;第六行变量依旧是未定义,修改不了;第八行是一个函数,此时就将第四行的函数块修改了。最后预解析保存的是第八行代码:function a (){ alert(4); }

    2、逐行解读。

    2-1、预解析过程后保存的代码是函数块,a=function a(){alert(4)},此时执行第一行代码,alert(a),那么就会弹出第八行代码。function a(){alert(4)}

    2-2、解读第二行代码,a=1,此时将函数代码块修改了,a=1,那么第三行代码则会弹出1;

    2-3、解读到第四行代码,是一个函数,没有调用,也就没有表达式,直接跳过执行第五行代码,依然是a=1;

    2-4、执行第六行代码,是一个表达式,将a修改为3;那么第七行代码就会弹出一个3

    2-5、执行到第八行代码时,是一个函数块,依旧没有调用,直接跳过执行第九行代码,所有最后弹出依旧是3

    所以最后的结果是:

    alert(a);					// function a (){ alert(4);}
    var a = 1;
    alert(a);					// 1
    function a (){ alert(2); }
    alert(a);					// 1
    var a=3;		
    alert(a);					// 3
    function a (){ alert(4); }
    alert(a);					// 3
    

    如果在最后再调用a()的话,会怎么样呢?答案是报错。因为最后执行的结果是一个a=3,是一个数字类型。用函数调用产生报错。 作用域的执行过程中,先找到整个作用域内的关键字或参数;然后再逐步解析。碰到调用的函数,我们根据执行顺序,再去解析被调用的函数块内部的代码。 当我们碰到函数作用域的时候,就有全局变量和局部变量之分,进而产生闭包和作用域链的知识。我们将会在后续陆续讨论。


    展开全文
  • 什么是作用域

    2020-03-29 13:16:12
    虽然对于许多新手开发者来说,作用域的概念并不是很容易理解,本文我会尽我所能用最简单的方式来解释作用域作用域链,希望大家有所收获! 作用域(Scope) 1. 什么是作用域 作用域是在运行时代码中的某些特定部分...
  • 作用域

    2020-06-20 12:09:58
    作用域:从表层上讲:就是在函数的里层作用域可以访问到外层作用域的变量。从底层上讲:就是在函数被执行的前一刻,会创建自己的[[scope]]对象。[[scope]]会保存当前作用域和上层作用域的变量和方法。函数自身的执行...
  • 几乎所有编程语言就是在变量中存储值,并且能读取和修改此值。事实上,在变量中存储值和取出值的能力,给程序赋予了状态。...常见的作用域主要分为几个类型:全局作用域、函数作用域、块状作用域、动态作...
  • Spring中bean的作用域与生命周期

    万次阅读 多人点赞 2020-05-13 10:07:56
    在Spring中,那些组成应用程序的主体及由Spring IoC容器所管理的对象,被称之为bean。简单地讲,bean就是由IoC容器初始化、装配及管理的对象,除此之外,bean就与应用程序中的其他对象没有什么区别了。...
  • 深入理解JavaScript中的作用域作用域链和闭包

    万次阅读 多人点赞 2018-05-14 17:00:19
    作用域先来谈谈变量的作用域 变量的作用域无非就是两种:全局变量和局部变量。 全局作用域: 最外层函数定义的变量拥有全局作用域,即对任何内部函数来说,都是可以访问的:&lt;script&gt; var outerVar...
  • JavaScript关于作用域作用域链和闭包的理解

    万次阅读 多人点赞 2017-04-30 16:26:10
    作用域先来谈谈变量的作用域 变量的作用域无非就是两种:全局变量和局部变量。 全局作用域: 最外层函数定义的变量拥有全局作用域,即对任何内部函数来说,都是可以访问的: var outerVar = "outer"; function ...
  •   作用域、上下文、执行期上下文、作用域链、闭包是JavaScript中关键概念之一,是JavaScript难点之一,在应聘面试时必定会问到的问题,作为前端工程师必须理解和掌握。相信大家已经阅读了很多关于这方面的文章,...
  • 作用域 本篇主要总结了作用域的定义、作用域作用域链的规则,全局变量和局部变量的关系,利用思维导图代替纯文字描述,提高收获,加油!
  • Js作用域作用域链详解

    万次阅读 多人点赞 2013-08-01 19:07:30
    一直对Js的作用域有点迷糊,今天偶然读到Javascript权威指南,立马被吸引住了,写的真不错。我看的是第六版本,相当的厚,大概1000多页,Js博大精深,要熟悉精通需要大毅力大功夫。 一:函数作用域  先看一小段代码...
  • Android 10适配要点,作用域存储

    万次阅读 多人点赞 2020-09-03 15:07:27
    在Android 10众多的行为变更当中,有一点是非常值得引起我们重视的,那就是作用域存储。这个新功能直接颠覆了长久以来我们一直惯用的外置存储空间的使用方式,因此大量App都将面临着较多代码模块的升级。然而,对于...
  • python作用域,变量作用域

    千次阅读 2019-07-02 20:47:24
    变量作用域 一个程序的所有变量并不是在哪个位置都可以访问的。访问权限取决于这个变量是在哪里赋值的。 变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。 如下为两种最基本的变量的作用域: ...
  • 任何程序设计语言都有作用域的概念,简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。在JavaScript中,变量的作用域有全局作用域和局部作用域两种。  1. 全局作用域...
  • 词法作用域、块作用域(已完结)

    千次阅读 2018-06-24 21:45:53
    作用域共有两种主要的工作模型——词法作用域和动态作用域,JS采用词法作用域 简单地说,词法作用域就是定义在词法阶段的作用域。换句话说,词法作用域是由你在写代码时将变量和块作用域写在哪里来决定的 由上面对...
  • js作用域作用域链概念理解及使用

    千次阅读 2016-07-12 15:50:46
    之前写过一篇JavaScript 闭包究竟是什么的文章理解闭包,觉得写得很清晰,可以简单理解闭包产生原因,但看评论都在说了解了作用域链和活动对象才能真正理解闭包,起初不以为然,后来在跟公司同事交流的时候发现作用...
  • JS中的块级作用域,var、let、const三者的区别

    万次阅读 多人点赞 2019-11-04 18:17:46
    首先,ECMAScript和JavaScript关系: ECMAScript是一个国际通过的标准化脚本语言。JavaScript由ECMAScript和DOM、BOM三者组成。...1. 块作用域{ }JS中作用域有:全局作用域、函数作用域。没有块作用域的概念。ECM
  • js作用域 作用域链 闭包

    千次阅读 2018-09-02 17:21:58
    作用域 变量 var声明的变量,其作用域是函数体的全部,没有块作用域 let声明的变量拥有块级作用域。 1) 局部变量: 函数内声明的变量为局部变量,为局部作用域,只能在函数内访问; function studentnum()...
1 2 3 4 5 ... 20
收藏数 754,391
精华内容 301,756
关键字:

作用域