javascript作用域
一 js的运行顺序 (先声明后赋值或执行)
如果一个文档流中包含多个script代码段(用script标签分隔的js代码或引入的js文件),它们的运行顺序是:
步骤1. 读入第一个代码段(js执行引擎并非一行一行地执行程序,而是一段一段地分析执行的)
步骤2. 做语法分析,有错则报语法错误(比如括号不匹配等),并跳转到步骤5
步骤3. 对var变量和function定义做“预解析”(永远不会报错的,因为只解析正确的声明)
步骤4. 执行代码段,有错则报错(比如变量未定义)
步骤5. 如果还有下一个代码段,则读入下一个代码段,重复步骤2
步骤6. 结束
编译过程:
编译型(c/java):词法分析,语法分析,语义检查,代码优化和字节生成。
解释型(js):词法分析,语法分析(得到语法树),引擎不同可能会有语义检查,代码优化等过程,没有字节生成(与编译型根本区别),执行。
语法树(Syntax Tree):可是理解为一种js对象结构,用来保存变量集(variables),方法集(functions)和作用域(scope)等。语法树保存在内存中,js的执行会按照语法树来执行。
JavaScript的作用域机制是词法作用域(lexcical scope)。就是作用域是定义时决定的而不是执行时决定的,即作用域取决于源码,通过静态分析就可以确定,所以也叫做静态作用域。但是with和eval无法仅通过静态技术实现,所以只能说javascript的作用域机制非常接近于词法作用域。
词法作用域的实现:就是作用域链(scope chain),是一中name lookup机制。
javascript在执行每个function时,会创建一个执行环境(execution context)。会先把此function定义时的作用域作为其scope chain,然后创建一个调用对象,并把它置于scope chain的顶部。这样本调用对象中的所有属性会覆盖掉上层作用域中的所有同名属性。
执行环境(execution context)是ECMAScript规范中的一个抽象概念。
js代码都是在执行环境中执行的,全局代码在“全局执行环境中”执行的。
当调用一个函数时,就会创建相应的执行环境,每一次调用一个函数或递归的调用相同函数都会创建一个执行环境,并且在函数的调用过程中都处于该执行环境中,当函数调用结束,执行环境会回到上一层的执行环境,其实就相当于形成了一个执行环境链(链表)。
创建执行环境:在这个过程中,会完成一系列的操作。
1 创建活动对象(call object)。活动对象是规范中规定的另外一种机制。它有可访问的命名属性,但是没有原型,而且不能通过js代码直接引用。
2 创建一个Arguments对象,这是一个伪数组对象,保存调用函数时传递的参数,有length(参数个数)和callee(函数引用)属性。然后会为活动对象创建一个名为"arguments"的属性,该属性引用前面创建的Arguments对象。
3 为执行环境分配作用域,从活动对象中取到作用域(scope)(活动对象创建时从语法树中直接得到),然后把当前活动对象置于作用域顶端,形成一个作用域链。
需要注意的是函数的形参也是会保存在语法树中变量集里的,因为语法树中所有变量集的值都是"undefined"。
个人认为Call Object翻译成活动对象比调用对象更为准确,因为活动对象里的变量是可变的,可以被赋值。
执行环境中包含当前的调用对象和作用域链。
执行环境中最重要的一点就是包含一个作用域链,这是一个对象链(链表结构),由全局对象和调用对象组成。
调用对象(call object),ECMAScript规范中称之为活动对象(active object)。是一个js结构,用来保存变量表,内嵌函数表(这些信息存在于语法树中,函数执行时,会把这些信息复制到活动对象中)。
with语句:ECMAScript规范中提供的用于修改作用域链的。with会计算一个表达式,该表达式如果是一个对象,那么就把这个对象置于当前作用域链的顶部。当执行完毕后回到原来的作用域链中。
当javascript查询变量时,会检查当前作用域的第一个对象,可能是活动对象或全局对象(window),如果有则返回,没有则沿作用域链检查下一个对象,直到window,没有则返回undefined。
经典例子
var i=10;
function a(){
alert(i);
var i = 2;
alert(i);
};
a();
运行结果?
结果是 undefined,2
当查找i时,会先从当前的活动对象中查找,根据js先声明后执行的运行顺序,在执行第一个alert(i)时,变量i已经被声明但没有被赋值,即值为undefined。此例中如果没有var i一句,即没有声明的话,js会沿作用域链查找window对象,则会返回10。
分享到:
相关推荐
JavaScript作用域是编程中至关重要的概念,它规定了变量和函数的可见性及生命周期。JavaScript主要有两种作用域:全局作用域和局部作用域。 全局作用域是指在代码的任何位置都可以访问的变量或函数,这通常包括在最...
JavaScript作用域是指在JavaScript代码中,变量、常量、对象和函数能够访问的范围。在编程中,变量和函数的使用都受到作用域的限制,决定了它们能够在哪些代码块中被引用。作用域有助于防止变量命名冲突,也使得程序...
深化理解javascript作用域其次篇之词法作用域和动态作用域_ 深化理解javascript作用域其次篇之词法作用域和动态作用域,是javascript中非常重要的一部分。理解词法作用域和动态作用域对javascript的编程至关重要。...
JavaScript作用域是编程中至关重要的概念,它定义了变量、函数和对象的可见性和生命周期。在JavaScript中,作用域主要分为两种类型:全局作用域和局部作用域。此外,随着ES6的引入,块级作用域和函数作用域也变得...
JavaScript作用域是编程中至关重要的概念,尤其是在JavaScript这种动态类型的脚本语言中。它规定了变量、函数以及其它标识符的可见性和生命周期,是代码组织和管理的关键元素。本资料"深入理解JavaScript作用域共12...
JavaScript作用域是编程中至关重要的概念,它规定了变量和函数的可见性和生命周期。了解JavaScript作用域对于编写高效、安全的代码至关重要。本篇将详细解释JavaScript作用域的几个核心特性,包括无块级作用域、函数...
JavaScript作用域原理是编程中的重要概念,它关乎变量的可见性、生命周期以及代码组织。本文将深入探讨JavaScript的作用域机制,特别是预编译的概念。在理解这些知识点之前,建议先回顾一下JavaScript的基础语法。 ...
### JavaScript作用域链(Scope Chain)初探 #### 一、引言 JavaScript的作用域链是一个重要的概念,尤其是在深入理解JavaScript执行机制时不可或缺的一部分。本文将通过对几个具体例子的分析来探讨JavaScript作用域...
01JavaScript作用域.md
深入理解JavaScript作用域
【温故而知新】JavaScript作用域
作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理。今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望能帮助大家更好的学习JavaScript。任何程序...
Javacript 中有一系列作用域的概念。对于新的JS的开发人员无法理解这些概念,甚至一些经验丰富的开发者也未必能。这篇文章主要目的帮助理解JavaScript中的一些概念如:scope,closure, this, namespace, function ...
第16周-第15章节-Python3.5-JavaScript作用域(二).avi