先看一个例子
var i=10;
function test(){
alert(i);
var i = 5;
}
test();//输出undefined
//预解析将 全局i和 test里面的i 都初始化为 undefined。 所以当 去掉test里面的 i 变量 将输出 10
如果你认为这个输出有问题的话,就有必要继续看下去了。
输出结果是undefined, 这种现象被称成“预解析”:JavaScript引擎会优先解析var变量和function定义。在预解析完成后,才会执行代码。如果一个文档流中包含多个script代码段(用script标签分隔的js代码或引入的js文件),运行顺序是:
step1. 读入第一个代码段,JavaScript执行引擎并非一行一行地执行程序,而是一段一段地分析执行的(以<\script\>标签来分割)
step2. 做语法分析,有错则报语法错误(比如括号不匹配等),并跳转到step5
step3. 对var变量做声明(初始为undefined)和function定义做“预解析”(永远不会报错的,因为只解析正确的声明)
step4. 执行代码段,有错则报错(比如变量未定义)
step5. 如果还有下一个代码段,则读入下一个代码段,重复step2
step6. 结束
在看几个小例子
alert(i);
var i = 1;
弹出undefined。预编译的时候,声明了变量i;执行到alert(i)这行代码的时候,i尚未被赋值,所以弹出undefined
alert(test1);//弹出function test1(){}
function test1(){}
alert(test2);//弹出undefined
var test2 =function(){};
对var变量做声明(初始为undefined)和function定义做“预解析”
下面看几个特殊的例子
alert(i);
i=10;
执行报错,i未定义。
alert(i);
eval("var i = 5;");
执行报错,i未定义。
小结
step3中所谓的“预解析”,其实是在step2的语法分析阶段完成,并存储在语法树中。当执行到函数实例时,会将varDelcs和funcDecls从语法树中复制到执行环境的scriptObject上。
step4中,未定义变量意味着在scriptObject的变量表中找不到,JS引擎会沿着scriptObject的upvalue往上寻找,如果都没找到,对于写操作i = 1; 最后就会等价为 window.i = 1; 给window对象新增了一个属性。对于读操作,如果一直追溯到全局执行环境的scriptObject上都找不到,就会产生运行期错误。
但需要注意,with和eval的语义无法仅通过静态技术实现,实际上,只能说JS的作用域机制非常接近lexical scope.
原文地址
http://leeldy.blog.163.com/blog/static/13985306201061325918669/
http://hi.baidu.com/lcgg110/blog/item/27c18bfa2a96908359ee908a.html
分享到:
相关推荐
### 浅析JavaScript原型继承机制 #### 一、引言 JavaScript作为一种动态语言,其对象模型与传统的面向对象编程语言有所不同。在JavaScript中,并没有直接提供类的概念,而是通过原型来实现继承。本文将深入探讨...
总结来说,尽管JavaScript不是一种传统的面向对象语言,但通过函数、原型和闭包等机制,它可以实现面向对象编程的关键特性,如封装、继承和多态。这使得JavaScript在Web开发中具有很高的灵活性和实用性。
接下来,我们将深入探讨JavaScript中的事件机制,这将有助于我们更好地理解如何在网页中实现用户交互。 首先,我们需要明白什么是事件。在计算机编程中,事件是指在运行程序时,某个特定的操作或动作发生时系统所...
JavaScript引擎是JavaScript代码得以运行的基础,它负责解释和执行代码。在深入理解JavaScript引擎工作机制时,我们需要掌握一些关键概念,如执行环境栈、全局对象、执行环境、变量对象、活动对象、作用域和作用域链...
Node.js是基于Chrome V8引擎的JavaScript运行环境,其最大的特色在于采用事件驱动、非阻塞I/O模型,使得Node.js适合处理大量并发的I/O操作,比如网络请求、文件操作等。而Node.js的模块加载机制是其能够高效运行的...
JavaScript的动态性允许在运行时修改对象的原型,这意味着可以随时添加或删除对象实例的方法。这提供了一种灵活的方式,但同时也可能造成复杂性和性能问题,因为查找属性可能需要遍历整个原型链。 6. **类的模拟**...
总结来说,JavaScript变量声明是一个多维度的话题,涵盖了声明方式、作用域、提升机制等关键概念。掌握这些概念对于编写清晰、健壮和可维护的JavaScript代码至关重要。在实际开发过程中,推荐使用let和const代替var...
### 浅析AMD、CMD与CommonJS规范——JavaScript模块化加载学习心得总结 #### 一、引言 在现代Web开发中,随着项目规模的不断扩大和技术复杂度的提高,JavaScript模块化成为了一种非常重要的编程实践。通过将复杂的...
此外,JavaScript的动态类型特性允许变量的类型在运行时改变,例如,一个Error对象可以被重新赋值为字符串,从而改变其类型。 在处理不同类型的数据时,需要注意类型转换的规则,例如,使用`Number()`、`parseInt()...
JavaScript中的作用域、执行上下文和闭包是理解JavaScript运行机制的关键概念。本文将深入探讨这些概念,并通过实例解析它们的工作原理。 首先,我们来看**词法作用域**。JavaScript遵循词法作用域规则,意味着变量...
`, `~`, `-`, `||`, `&&`等一元操作符在函数前面的使用,主要是为了将函数表达式转换为一个可以立即执行的形式,避免了函数声明和执行的混淆,同时也提供了封装和隔离作用域的机制。理解这一特性有助于编写更加灵活...
JavaScript异步加载浅析 在Web开发中,JavaScript的加载方式对用户体验和页面性能有着显著影响。主要关注的两个核心问题是同步脚本和异步脚本的加载与执行顺序,以及由此带来的性能优化问题。 首先,同步脚本的...
标题《js模块加载方式浅析》和描述为我们展开了一场关于JavaScript模块化加载方式的探索之旅。文章标题明确指出了内容的核心,即通过简单易懂的方式讲述前端JavaScript模块的加载机制。而在描述部分,作者强调了内容...
### 浅析JQuery框架及其插件应用 #### 一、jQuery框架概述 JQuery,一个由美国程序员John Resig创建的JavaScript库,自诞生以来迅速成为全球开发者钟爱的工具之一。它以“写得少,做得多”(WRITELESS,DOMORE)的...
Node.js 的每一个 API 都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发。 Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现。 Node.js 单线程类似进入一个while(true)的事件循环,...
2. **运行机制**: 当我们通过`java 类名`命令运行一个Java程序时,JVM(Java Virtual Machine)会查找包含`main()`方法的`public`类,并执行其中的`main()`方法。由于`main()`是静态的,所以无需实例化类对象,JVM...
【基于OBPM构建企业办公管理系统原理浅析】 随着信息技术的发展,企业越来越重视信息化在办公管理中的应用,以提升效率和管理水平。OBPM(Open Business Process Management,开源业务流程管理)作为一种开源、轻量...
JavaScript 中的事件处理机制主要包括事件监听器的绑定与触发。 #### 二、基本的事件绑定方式 1. **内联绑定**: - 这是最简单的绑定方式,直接在HTML标签中定义事件处理器。 ```html ()">test function ...
Node.js是一种基于Chrome V8引擎的JavaScript运行环境,它使得JavaScript能够运行在服务器端。随着网络技术的快速发展,数据传输安全成为了一个不可忽视的问题。本文将详细解析Node.js在数据加密传输中的应用,特别...