`

浅析JS全局变量与局部变量 执行环境 作用域链 JS解释器执行过程

 
阅读更多
参考http://hi.baidu.com/cjry_8854/item/585b445f577aab3494eb0513
这里列出几个值得注意的地方
一全局变量 变量的声明
JS解释器开始运行时,在执行任何JS代码前,会创建一个全局对象,并且JS解析器会在相应的代码段里寻找var声明的变量,把这个var声明的变量作为全局对象的属性(在函数中它也作为调用对象的属性),并初始化为undefined。

也就是说当var声明一个JS全局变量时,实际上就是定义了一个全局对象的属性,或者反过来说,这个全局对象的属性就是JS全局变量。当然JS解释器还会用预定义的值和函数来初始化全局对象的许多属性,如:Infinity parseInt Math。在非函数内部可以用this来引用这个全局对象,还要注意window和this的区别,在客户端的JS中,Window对象代表浏览器窗口,它包含该窗口中的所有JS代码的全局对象,具有自我引用的window属性。

重复的var声明不会造成任何错误 var声明只是方便创建全局对象,调用对象的属性,代码只是赋值用的

遗漏的声明:给未声明的变量赋值,JS会隐式声明全局变量(在全局对象中增加相应的属性),然后给其赋值

二.变量作用域
1.局部变量和全局变量同名时,会隐藏这个全局变量。
2.函数没有块级作用域,函数中声明的变量,无论在哪里声明的,在整个函数中它们都是有定义的。
3.未声明的变量和未赋值的变量:alert(u);会产生一个错误--使用未声明的变量会产生一个错误
var u;alert(u);会跳出undefined---使用未赋值的变量,使用的它的默认值undefined

三 局部变量:调用对象
1.函数的局部变量作为调用对象的属性,调用对象是一个完全独立的对象,它独立于全局对象,所以可以防止覆盖同名的全局变量。

四 JS的执行环境
1.JS解释器执行一个函数时,会创建一个执行环境。JS允许同时存在多个全局执行环境,如:JS客户端的ifame的情况。

执行环境定义了变量或函数有权访问的其他数据,决定了他们各自的行为。每个执行环境都有一个与之相关联的变量对象,执行环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。
可见http://blog.163.com/tracy_hyq/blog/static/2084161872012529112624447/
这里要注意,在上面的博客中和一些其他书籍中所说的变量对象就可以理解为这里的全局对象和调用对象,那里的活动对象可以理解为这里的调用对象。

五JS的执行过程
具体可参见http://hi.baidu.com/cjry_8854/item/585b445f577aab3494eb0513

在JS解释器执行任何代码之前,创建全局对象
    用预定义的值和函数来初始化全局对象中的属性,eg.Math,Infinity,parseInt
    搜索函数外的var声明,创建全局对象相应的属性,初始化为undefined
  创建全局的执行环境,作用域链只有一个对象-全局对象
  依次执行代码
    遇到var声明赋值语句给全局对象相应的属性赋值
    遇到未声明赋值语句,在全局对象中查找是否已有该属性,如果没有,增加相应的属性,最后赋值
    遇到函数调用,创建调用对象
      搜索函数中的var声明和参数,创建调用对象相应的属性,初始化为undefined
      创建函数执行环境,作用域链--第一对象:调用对象;第二对象:全局对象
      依次执行代码
        遇到var声明赋值语句给调用对象相应的属性赋值
        遇到未声明赋值语句,在全局对象中查找是否已有该属性,如果没有,增加相应的属性,最后赋值
        遇到函数调用,创建嵌套函数的调用对象
          搜索嵌套函数中的var声明和参数,创建嵌套函数的调用对象相应的属性,初始化为 undefined
          创建嵌套函数执行环境,作用域链--第一对象:嵌套函数的调用对象;第二对象:调用                 对象;第三对象:全局对象

我的总结,先创建变量对象,搜索代码,找寻声明的赋值语句(注意是用var声明的赋值语句,未用var声明的赋值语句的属性在执行时才加入到全局对象中),创建执行环境、作用域,依次执行代码。

同时我们还应该注意
第一:在javascript的预解析中,除了对var 变量的预定义,还包括了提取对函数的定义,所以可以在script的任何地方定义函数,在任何地方调用。不限于它之前,而JS还有种函数的定义方式为字面量定义法,如
alert(typeof y3); //结果为undefined
var y3 = function (){ 
  console.log('1'); 
}

javascript 引擎在预解析 var 时 会给他们一个初始值 undefined,这样一来,如果我们在它的声明之前调用它,javascript 引擎还没拿到它的真实值,自然会报"xxx is not a function" 的错。
这就是为什么函数的调用一定要在函数的字面定义法的声明之后的原因了。
第二:javascript 在预解析时function的声明优先级比var的高。
alert(typeof y5);
var y5 = 'angle';
function y5(){
console.log('ghost'); 
}
alert(y5);
/*首先同样的y5,由于function的声明优先级高,所以其弹出的类型为function,但是当第二次alert时,其值已赋值为angle。
*/
分享到:
评论

相关推荐

    浅析JavaScript作用域链、执行上下文与闭包

    了解闭包之前,我们先理解**变量作用域**。在JavaScript中,有全局作用域和局部作用域。全局变量在整个脚本中都有效,而函数内的变量(通过`var`声明)是局部的,仅在函数内部可用。如果函数内部有同名变量,局部...

    浅析php变量作用域的一些问题

    PHP的变量作用域规则与C语言有所不同,可能导致初学者在处理全局变量和局部变量时遇到困扰。 首先,PHP中的变量主要分为四种作用域: 1. **全局(Global)作用域**:在函数外部定义的变量,可以在整个脚本中访问,...

    深入浅析JavaScript中的作用域和上下文

    JavaScript中,作用域和上下文是理解代码执行逻辑的关键概念。作用域指的是变量和函数的可见性和生命周期,而上下文则关乎`this`关键字的值,它指示了当前代码执行的环境。 **作用域(Scope)** 1. **全局作用域**...

    深化浅析JavaScript中的作用域和上下文_.docx

    **变量作用域**: 在JavaScript中,变量可以存在于全局作用域或局部作用域。全局变量在整个程序运行期间都是可访问的,而局部变量只在定义它的函数内部有效。在ES6之前,JavaScript没有块级作用域,但ES6引入了`let`...

    浅析JavaScript中作用域和作用域链

    作用域链是由当前执行环境的变量对象和所有包含它的父级执行环境的变量对象组成的链式结构。如果在当前作用域找不到变量,就会向上级作用域查找,直至找到全局作用域。如果在全局作用域仍找不到,变量的值将被视为`...

    浅析JavaScript中的变量复制、参数传递和作用域链

    由于每次查找变量都需要遍历作用域链,过多的全局变量会增加查找时间,因此推荐将变量尽可能地限制在局部作用域内。 理解这些基本概念对于深入学习JavaScript的高级特性至关重要,如闭包、原型链和继承。闭包依赖于...

    浅析js封装和作用域

    如果直接使用全局变量可能会引起冲突,这时通过封装和合理的作用域设置,可以有效避免这些问题: ```javascript var myModule = (function() { var privateVar = "I am private"; function privateMethod() { //...

    浅析JavaScript声明变量

    使用var关键词声明变量的作用域是当前的执行上下文,有可能是外围函数,或者,当变量声明在函数体之外时,则为全局变量。 定义在函数体外的都属于全局变量,定义在函数体内的属于局部变量。这里的定义是指通过var...

    深化浅析JavaScript中数据共享和数据传递_.docx

    2. JavaScript全局变量:在Page作用域中,可以通过定义全局变量实现数据共享。尽管可以直接定义全局变量(不使用`var`关键字)或者将其附加到`deviceone`对象上,但这不被推荐,因为容易导致命名冲突和调试困难。 ...

    JS变量提升原理与用法实例浅析

    一个例子: (局部变量与全局变量同名时 , 局部变量覆盖全局变量) var a=全局变量; function test() { [removed]ln(a); var a=局部变量; [removed]ln(a); } test(); 上例的两个输出结果是 undefined局部变量 第...

    浅析javascript语言中的函数闭包现象.pdf

    JavaScript中的函数闭包是一个重要的概念,它涉及到函数的作用域、变量持久化以及内存管理等多个方面。闭包的本质是在函数内部创建另一个函数,使得内部函数能够访问并操作外部函数的局部变量,即使外部函数已经执行...

    浅析php中常量,变量的作用域和生存周期

    4. **超全局变量**(Super Global Variables):这些变量在整个脚本中始终可用,无论在哪一层作用域内,包括所有函数内部。例如,`$_GET`用于获取通过GET方式传递的参数,`$_POST`用于POST方式,`$_SESSION`用于管理...

    Javascript 引擎工作机制详解

    在深入理解JavaScript引擎工作机制时,我们需要掌握一些关键概念,如执行环境栈、全局对象、执行环境、变量对象、活动对象、作用域和作用域链。 首先,全局对象(Global Object)是JavaScript环境中最初创建的对象...

    理解Javascript_12_执行模型浅析

    函数执行环境则与每个函数调用关联,为函数提供独立的作用域。 在每个执行环境中,都会有一个Variable Object(变量对象),它存储了环境中的变量和函数声明。对于全局执行环境,Variable Object等同于Global ...

    Javascript自执行匿名函数(function() { })()的原理浅析_.docx

    自执行匿名函数能够有效地隔离局部变量,避免它们泄露到全局作用域中,从而减少了潜在的安全风险。例如,在使用第三方库或框架时,通过这种方式定义函数可以帮助我们避免与现有代码产生命名冲突的问题。 #### 实际...

    浅析javascript异步执行函数导致的变量变化问题解决思路

    总的来说,JavaScript的异步执行可能导致变量共享和作用域问题,特别是在循环中。解决这些问题的关键在于理解和利用作用域、闭包以及适当的变量声明方式,例如IIFE或使用`let`关键字。理解这些概念对于编写健壮的...

    浅析JavaScript中命名空间namespace模式_.docx

    JavaScript中的命名空间(namespace)模式是一种组织代码结构的策略,特别是在使用多个库或框架时,避免全局变量冲突和提高代码可维护性。由于JavaScript没有像C#或Java那样的内置命名空间支持,开发者需要通过...

Global site tag (gtag.js) - Google Analytics