js 词法分析,词法作用域

先来看个常见的面试题如下:

var a = 10;
function test(){
    alert(a);  //undefined
    var a = 20;
    alert(a); //20
}
test();

疑问:为什么呢?test()执行时,虽然a=20没有赋值,但是父级作用域里是有a=10的,不应该是undefined呀,js是按顺序执行的,此时的var num = 20;根本没有执行,所以应该是10!!你是不是也是这么认为的,就和我当初一样???

分析:众所周知,js代码是自上而下执行的,JavaScript并不是传统的块级作用域,而是函数作用域。JavaScript引擎会在代码执行前进行词法分析,所以事实上,js运行分为此法分析和执行两个阶段。

JavaScript代码运行前有一个类似编译的过程即词法分析,词法分析主要有三个步骤:

  • 分析参数
  • 再分析变量的声明
  • 分析函数声明

具体步骤如下:

函数在运行的瞬间,生成一个活动对象(Active Object),简称AO

第一步:分析参数:

  1. 函数接收形式参数,添加到AO的属性,并且这个时候值为undefined,即AO.name=undefined
  2. 接收实参,添加到AO的属性,覆盖之前的undefined

第二步:分析变量声明:如var name;或var name=‘mary‘;

  1. 如果上一步分析参数中AO还没有name属性,则添加AO属性为undefined,即AO.name=undefined
  2. 如果AO上面已经有name属性了,则不作任何修改

第三步:分析函数的声明:

如果有function name(){}把函数赋给AO.name ,覆盖上一步分析的值

分析下面这个栗子:

1.var a = 10;
2.function test(a){
3.    alert(a);           //function a (){}
4.    var a = 20;
5.    alert(a);           //20
6.    function a (){}
7.    alert(a);           //20
8.    }
9.
10.test(100);

词法分析:

第一步,分析函数参数:

 形式参数:AO.a = undefined
 接收实参:AO.a = 100

第二步,分析局部变量:

第4行代码有var a,但是此时已有AO.a = 100,所以不做任何修改,即AO.a = 100

第三步,分析函数声明:

第6行代码有函数a,则将function a(){}赋给AO.a,即AO.a = function a(){}

执行代码时:

第3行代码运行时拿到的a时词法分析后的AO.a,即AO.a = function a(){};
第4行代码:将20赋值给a,此时a=20;
第5行代码运行时a已经被赋值为20,结果20;
第6行代码是一个函数表达式,所以不做任何操作;
第7行代码运行时仍是20;

ps:

1.var a = 10;
2.function test(a){
3.    var a;               //证明词法分析第二步。
4.    alert(a);           //100
5.    a = 20;
6.    alert(a);           //20
7.}
7.test(100);

ps:

var a = 10;
function test(a){
    alert(a);         //100
    var a = 20;
    alert(a);         //20
    a = function(){}        //是赋值,只有在执行时才有效
    alert(a);         //function(){}
}
test(100);

ps:(执行结果同上)

var a = 10;
function test(a){
    alert(a);                //100
    var a = 20;
    alert(a);                //20
    var a = function(){}        //是赋值,只有在执行时才有效
    alert(a);                //function(){}
}
test(100);

补充说明:函数声明与函数表达式

//函数声明
function a(){
}
//函数表达式
var b = function(){
}

a和b在词法分析时,区别:

a在词法分析时,就发挥作用;
b只有在执行阶段,才发挥作用。

词法作用域

所谓词法作用域是说,其作用域为在定义时(词法分析时)就确定下来的,而并非在执行时确定。白话就是在函数未执行前,函数执行的顺序已经被确定,而不是类似JAVA一样,是在执行前根本不知道执行顺序。

原文地址:https://www.cnblogs.com/jlfw/p/12220737.html

时间: 2024-10-31 10:30:05

js 词法分析,词法作用域的相关文章

JS的词法作用域

词法作用域定义实现的规则: 1 函数作用域实在定义的时候决定的,而不是在执行时候决定 2 为了实现这种词法作用域,函数内部不仅包含函数代码逻辑,还必须引用当前的作用域链. 3 函数对象可以通过作用域链相互关联起来,函数内部的变量都可以保存在函数作用域内. 变量作用域:变量的作用域是程序源代码中定义这个变量的区域. 1在函数内部,局部变量的优先级要高于同名的全局变量. 2 JS是函数作用域 3 函数作用域:变量在声明它的函数体内以及该函数内部嵌套的函数体内都有定义. 4 JS的函数作用域指的是:在

js 欺骗词法作用域

如果词法作用域完全由写代码期间函数所声明的位置来定义,怎样才能在运行时来"修改"(也可以说欺骗)词法作用域呢?    JavaScript 中有两种机制来实现这个目的.社区普遍认为在代码中使用这两种机制并不是什么好注意.但是关于它们的争论通常会忽略掉最重要的点:欺骗词法作用域会导致性能下降.在详细解释性能问题之前,先来看看这两种机制分别是什么原理 1.eval JavaScript 中的 eval(..) 函数可以接受一个字符串为参数,并将其中的内容视为好像在书写时就存在于程序中这个位

js 中采用词法作用域

所谓的 词法( 代码 )作用域, 就是代码在编写过程中体现出来的作用范围. 代码一旦写好, 不用执行, 作用范围就已经确定好了. 这个就是所谓词法作用域. 在 js 中词法作用域规则: 1.函数允许访问函数外的数据. 2.整个代码结构中只有函数可以限定作用域. 3.作用规则首先使用提升规则分析. 4.如果当前作用规则中有名字了, 就不考虑外面的名字. 在编译语言中,**通常** 代码在被引擎执行之前会经历三个步骤: 1. 词法分析(tokenzing/lexing)2. 解析/语法分析(pars

js词法作用域

词法作用域就是说在词法分析的时候就已经形成了的作用域.这个时候已经定死了.如果一个函数在全局里面声明了,她的父级作用域就是全局作用域.一个函数的作用域只有可能存在于一个父级作用域里面.不会同时存在两个父级作用域. var a = 2; function foo() { console.log( a ); console.log(this.a); console.log(this); } function bar() { var a = 3; foo(); } bar(); //2. 2. win

区分词法作用域(js)与动态作用域(精!)

在js学习中,词法作用域是必须要掌握的! 在这里,我将总结一下<你不知道的JS>一书中词法作用域的重点并分享给大家! 首先带来一段代码示例: function foo(){ console.log(a);//2 } function bar(){ var a = 3; foo(); } var a = 2; bar(); js词法作用域输出结果:"2"; 动态作用域输出结果:"3" 下面我将对两种作用域的输出结果进行分析: #在对结果分析之前首先我们要了

JS中函数的词法作用域

在javascript中,每一个函数都拥有自己的词法作用域.简单理解就是,每个函数在被定义(注意不是调用!)时,都会创建一个属于自己的环境(作用域). 比如, function foo(){ var a = 1; foo2(); } function foo2(){ console.log(a); }fon(); 运行结果: ReferenceError: fon is not defined. 因为,函数foo2在被定义时,它可以访问的环境只有全局作用域和它自己的函数作用域,并不能访问到函数f

[label][JavaScript]读nowmagic - js词法作用域、调用对象与闭包

原文链接:                 http://www.nowamagic.net/librarys/veda/detail/1305 作用域(scope) JavaScript 中的函数属于词法作用域,也就是说函数在它被“定义时”的作用域中运行,而不是在“被执行时”的作用域内运行. 什么是“定义时”? 什么是 “被执行时”? 定义时: 一个函数A在“定义时”就是 function A() { }这个语句执行的时候,就是定义这个函数的时候. 被执行时: A“被执行时”(被调用的时侯)是

js 函数作用域, 块级作用域和词法作用域

函数作用域, 块级作用域和词法作用域 0 作用域: 0.1 作用域是程序源代码中定义变量的区域. 0.2 作用域规定了如何查找变量,也就是确定当前执行代码对变量的访问权限. 0.3 ECMAScript6之前只有全局作用域和函数作用域. 0.4 JavaScript采用词法作用域(lexical scoping),也就是静态作用域. var scope = "global scope"; function checkscope(){ var scope = "local sc

你不知道的JS系列 ( 5 ) - 词法作用域

作用域分为两种,一种是词法作用域,一种是动态作用域,我们先看第一种,词法作用域 词法作用域就是定义在词法阶段的作用域(编译器的第一个工作阶段叫做词法化,词法化的过程会对源代码中的字符进行检查).换句话说,词法作用域是由你在写代码时将变量和块作用域写在哪里来决定的.因此词法分析器处理代码时会保持作用域不变 function foo(a) { var b = a * 2; function bar(c){ console.log( a, b, c ); } bar( b * 3 ); } foo(