加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 湛江站长网 (https://www.0759zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 创业 > 正文

javascript的词法作用域

发布时间:2018-10-07 10:44:01 所属栏目:创业 来源:站长网
导读:副标题#e# 大家应该写过下面类似的代码吧,其实这里我想要表达的是有时候一个方法定义的地方和使用的地方会相隔十万八千里,那方法执行时,它能访问哪些变量,不能访问哪些变量,这个怎么判断呢?这个就是我们这次需要分析的问题词法作用域 var classA = fu
副标题[/!--empirenews.page--]

大家应该写过下面类似的代码吧,其实这里我想要表达的是有时候一个方法定义的地方和使用的地方会相隔十万八千里,那方法执行时,它能访问哪些变量,不能访问哪些变量,这个怎么判断呢?这个就是我们这次需要分析的问题——词法作用域

var classA = function(){
    this.prop1 = 1;
}
classA.prototype.func1 = function(){
    var that = this,
        var1 = 2;
 
    function a(){
        return function(){
            alert(var1);
            alert(this.prop1);
        }.apply(that);
    };
    a();
}
var objA = new ClassA();
objA.func1();

词法作用域:变量的作用域是在定义时决定而不是执行时决定,也就是说词法作用域取决于源码,通过静态分析就能确定,因此词法作用域也叫做静态作用域。 with和eval除外,所以只能说JS的作用域机制非常接近词法作用域(Lexical scope)。

下面通过几个小小的案例,开始深入的了解对理解词法作用域和闭包必不可少的,JS执行时底层的一些概念和理论知识。

经典案列重现

1、经典案例一

/*全局(window)域下的一段代码*/
function a(i) {
    var i;
    alert(i);
};
a(10);

疑问:上面的代码会输出什么呢?
答案:没错,就是弹出10。具体执行过程应该是这样的

a 函数有一个形参 i,调用 a 函数时传入实参 10,形参 i=10
接着定义一个同名的局部变量 i,未赋值
alert 输出 10

思考:局部变量 i 和形参 i 是同一个存储空间吗?

2、经典案例二

/*全局(window)域下的一段代码*/
function a(i) {
    alert(i);
    alert(arguments[0]); //arguments[0]应该就是形参 i
    var i = 2;
    alert(i);
    alert(arguments[0]);
};
a(10);

疑问:上面的代码又会输出什么呢?(( 10,10,2,10 || 10,10,2,2 ))
答案:在FireBug中的运行结果是第二个10,10,2,2,猜对了… ,下面简单说一下具体执行过程

a 函数有一个形参i,调用 a 函数时传入实参 10,形参 i=10
第一个 alert 把形参 i 的值 10 输出
第二个 alert 把 arguments[0] 输出,应该也是 i
接着定义个局部变量 i 并赋值为2,这时候局部变量 i=2
第三个 alert 就把局部变量 i 的值 2 输出
第四个alert再次把 arguments[0] 输出

思考:这里能说明局部变量 i 和形参 i 的值相同吗?

3、经典案例三

/*全局(window)域下的一段代码*/
function a(i) {
    var i = i;
    alert(i);
};
a(10);

疑问:上面的代码又又会输出什么呢?(( undefined || 10 ))
答案:在FireBug中的运行结果是 10,下面简单说一下具体执行过程

第一句声明一个与形参 i 同名的局部变量 i,根据结果我们知道,后一个 i 是指向了
形参 i,所以这里就等于把形参 i 的值 10 赋了局部变量 i
第二个 alert 当然就输出 10

思考:结合案列二,这里基本能说明局部变量 i 和形参 i 指向了同一个存储地址!

4、经典案例四

/*全局(window)域下的一段代码*/
var i=10;
function a() {
    alert(i);
    var i = 2;
    alert(i);
};
a();

疑问:上面的代码又会输出什么呢?(小子,看这回整不死你!哇哈哈,就不给你选项)
答案:在FireBug中的运行结果是 undefined, 2,下面简单说一下具体执行过程

第一个alert输出undefined
第二个alert输出 2

思考:到底怎么回事儿?

5、经典案例五…………..N

看到上面的几个例子,你可能会想,怎么可能,我写了几年的 js 了,怎么这么简单例子也会犹豫,结果可能还答错了。其实可能原因是:我们能很快的写出一个方法,但到底方法内部是怎么执行的呢?执行的细节又是怎么样的呢?你可能没有进行过深入的学习和了解。要了解这些细节,那就需要了解 JS 引擎的工作方式,所以下面我们就把 JS 引擎对一个方法的解析过程进行一个稍微深入一些的介绍

代码解析过程

1、javascript执行顺序

编译型语言,编译步骤分为:词法分析、语法分析、语义检查、代码优化和字节生成。
解释型语言,通过词法分析和语法分析得到语法分析树后,就可以开始解释执行了。这里是一个简单原始的关于解析过程的原理,仅作为参考,详细的解析过程(各种JS引擎还有不同)还需要更深一步的研究
JavaScript执行过程,如果一个文档流中包含多个script代码段(用script标签分隔的js代码或引入的js文件),它们的运行顺序是:

  1. 读入第一个代码段(js执行引擎并非一行一行地执行程序,而是一段一段地分析执行的)
  2. 做词法分析和语法分析,有错则报语法错误(比如括号不匹配等),并跳转到步骤5
  3. 对【var】变量和【function】定义做“预解析“(永远不会报错的,因为只解析正确的声明)
  4. 执行代码段,有错则报错(比如变量未定义)
  5. 如果还有下一个代码段,则读入下一个代码段,重复步骤2
  6. 结束

2、特殊说明

全局域(window)域下所有JS代码可以被看成是一个“匿名方法“,它会被自动执行,而此“匿名方法“内的其它方法则是在被显示调用的时候才被执行

3、关键步骤

上面的过程,我们主要是分成两个阶段

javascript解析:就是通过语法分析和预解析构造合法的语法分析树。
javascript执行:执行具体的某个function,JS引擎在执行每个函数实例时,都会创建一个执行环境(ExecutionContext)和活动对象(activeObject)(它们属于宿主对象,与函数实例的生命周期保持一致)

3、关键概念

到这里,我们再更强调以下一些概念,这些概念都会在下面用一个一个的实体来表示,便于大家理解

语法分析树(SyntaxTree):可以直观地表示出这段代码的相关信息,具体的实现就是JS引擎创建了一些表,用来记录每个方法内的变量集(variables),方法集(functions)和作用域(scope)等。

执行环境(ExecutionContext):可理解为一个记录当前执行的方法【外部描述信息】的对象,记录所执行方法的类型,名称,参数和活动对象(activeObject)。

(编辑:PHP编程网 - 湛江站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读