`
指甲刀X
  • 浏览: 35017 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

图解javascript中的变量对象、闭包、作用域链机理

阅读更多

        javascript中的闭包是一个强大而灵活的武器,搞清闭包,作用域链的作用机理,能让我更好的将闭包运用在我们的项目中。

 

        先看一个闭包在for循环中经典的应用:

function foo(){
	for(var i = 0; i<10; i++){
		(function(j){
			setTimeout(function(){
				console.log( "current i:" + j + "--" + new Date().getSeconds() + "s" );
			}, j * 1000);
		})(i);
    }
}

foo();
 

       上面的代码改自Pro JavaScript Techniques 中用js控制css达到动画效果的部分。动画的高度/透明度是根据索引i的值动态设置的,所以我们需要将这个索引i保存下来。这里就有一个问题,为什么我们写成下面的代码就不能得到正确的索引呢?

function foo(){
	for(var i = 0; i<10; i++){
		setTimeout(function(){
				console.log("current i:"+i+"--"+new Date().getSeconds()+"s");     //其实这里也是一个闭包
		},i*1000);
    }
}

foo();

       上面的代码得到的i始终是10,而不是想要的1,2,3...

       现在我们来逐步详细分析原因。

       1. 进入foo的execution context阶段;

            这时创建foo的Variable Object (VO)/Activation Object (AO)

VO(foo) = {
  i: undefined,
};

        2. foo代码执行阶段

            将fooExecutionContext push进Execution Context Stack 中,

            i随着循环被修改为相应的数值。

executionContextStack.push(fooExecutionContext);

executionContextStack = [ 
<foo> functionContext,
globalContext
]
 

         由于在for循环执行的时候,setTimeout内部的匿名函数的execution context对于foo来说是不可见的,因为这时的匿名函数并没有执行, 不能访问、修改该匿名函数内部的变量,所以匿名函数中的i不会被修改为for循环的当前索引。 但是该匿名函数的Variable Object (VO)/Activation Object (AO)已经创建,并且保存了i的引用

       for循环结束时i值为10, 正是由于匿名函数的VO/AO保存了i的引用,foo运行结束时,Garbage Collector不会销毁foo的VO/AO(上面保存着i=10),所以当setTimeout内的匿名函数运行时,i的值始终为10。

 

        搞清楚了上面的问题后,现在我们用图来解释开始的例子

js 运行机理

图 1

上面的图是foo在执行最后一次循环时的运行机理。

图 2

图2是setTimeout内部匿名函数执行时的机理,其中红颜色框起来部分随每个 setTimeout内部匿名函数的不同而不同。

 

 

        通过上面两副图我们可以清楚的看到,增加的匿名自执行函数的作用就是将for循环的索引作为自己的局部变量保存起来,这样setTimeout里面的匿名函数就可以通过scope chain访问到正确的索引值了。

 

参考:

http://dmitrysoshnikov.com/ecmascript/javascript-the-core/

http://dmitrysoshnikov.com/ecmascript/chapter-1-execution-contexts/

http://dmitrysoshnikov.com/ecmascript/chapter-2-variable-object/

http://dmitrysoshnikov.com/ecmascript/chapter-4-scope-chain/

 

  • 大小: 49.2 KB
  • 大小: 34.3 KB
分享到:
评论

相关推荐

    深入Javascript函数、递归与闭包(执行环境、变量对象与作用域链)使用详解

    本文将深入探讨JavaScript中的函数、递归和闭包,以及执行环境、变量对象与作用域链的概念。 首先,我们来看JavaScript中定义函数的两种方式:函数声明和函数表达式。函数声明是一种明确的、独立的代码结构,例如`...

    深入理解JavaScript作用域和作用域链

    作用域链是JavaScript中另一个核心概念,它是由函数创建时的作用域决定的,包含了函数被创建时所有可访问的数据对象。这个链由内部属性[[Scope]]定义,它包含了函数定义时所在作用域的对象集合。当函数执行时,会...

    夯实基础中篇-图解作用域链和闭包.doc

    首先,**作用域链**是JavaScript中的一种机制,它定义了变量和函数查找的顺序。当尝试访问一个变量时,JavaScript会首先在当前执行上下文中查找,如果找不到,它会沿着执行上下文的外部引用(outer)向上搜索,直到...

    图解Javascript——作用域、作用域链、闭包

    作用域链的头部是最接近当前执行环境的变量对象,即当前正在执行函数的活动对象(AO),而链的尾部则是全局活动对象(globalAO)。当代码试图访问一个变量时,JavaScript引擎会顺着作用域链向上查找,直到找到该变量...

    JavaScript中作用域链的概念及用途讲解

    JavaScript中的作用域链是编程中一个至关重要的概念,它决定了变量和函数的可访问性以及在不同作用域内的查找顺序。在深入理解作用域链之前,我们首先要了解什么是执行环境和变量对象。 执行环境,简单来说,就是...

    javascript 闭包、匿名函数、作用域链

    JavaScript中的闭包、匿名函数和作用域链是编程中至关重要的概念,它们是理解JavaScript运行机制的关键。在本文中,我们将深入探讨这三个概念,并通过实际示例来展示它们的运用。 首先,我们来讨论“闭包”。闭包是...

    10-作用域链和闭包:代码中出现相同的变量,JavaScript引擎是如何选择的?_For_vip_user_0011

    "作用域链和闭包:代码中出现相同的变量,JavaScript引擎是如何选择的?" 标题“作用域链和闭包:代码中出现相同的变量,JavaScript引擎是如何选择的?”中,我们可以看到JavaScript引擎是如何选择相同的变量的。...

    深入了解JavaScript,优化作用域链(2).pdf

    此外,闭包是JavaScript中一个重要的概念,它允许函数访问外部函数作用域中的变量。闭包在保持变量引用的同时也阻止了变量所在作用域的销毁。这可能会导致内存泄漏,特别是在全局作用域中创建闭包的情况下。因此,...

    JavaScript中的作用域链和闭包

    **作用域链**是JavaScript中用于决定变量访问的一个机制。每个函数在创建时,都会形成一个作用域链,这个链由当前函数的作用域(包含局部变量)和所有父级作用域(直至全局作用域)组成。作用域链确保了函数能够访问...

    JavaScript作用域、闭包、对象与原型链概念及用法实例总结

    JavaScript是Web开发中不可或缺的一部分,它提供了丰富的特性,如作用域、闭包、对象和原型链,这些都是理解和编写高效代码的关键。以下是对这些概念的详细解释: 1. **JavaScript变量作用域** - **函数作用域**:...

    深入理解变量作用域

    - 定义:在JavaScript中,如果一个变量在任何函数外部声明,则该变量处于全局作用域下。这意味着它可以在程序的任何地方被访问。 - 特性: - 全局变量在整个程序运行期间都是可用的。 - 当一个变量被声明但未被...

    基于JavaScript的变量作用域的辨析.pdf

    本文探讨了JavaScript中的变量作用域问题,通过对两种变量的特性从不同角度进行分析和测试,讨论了如何控制变量作用域的有效方法。 变量作用域是JavaScript编程过程中经常遇到的问题之一,对于编程人员来说是一个...

    闭包作用域

    在JavaScript中,闭包(Closure)是一个非常重要的概念,它允许一个函数访问并操作其外部作用域中的变量,即使该函数在其外部作用域之外被调用。这种特性使得闭包成为一种强大的工具,能够实现诸如数据封装、私有...

    深度探讨javascript函数的原型链和闭包

    闭包是理解作用域链的关键概念,它允许内部函数记住其定义时的作用域,即使外部函数已经完成执行。闭包常常用于封装变量和实现私有方法,提高代码的封装性和安全性。 总结一下,JavaScript中的函数不仅是一种数据...

    图解javascript作用域链

    在JavaScript中,每个函数都有自己的作用域,而这些作用域按照特定的顺序组织起来,形成了作用域链。这个链帮助解析器在不同层级的上下文中找到变量。 在提供的代码示例中,我们有一个`window.onload`事件处理器,...

    学习python中变量作用域及嵌套作用域.pdf

    Python 中的变量作用域可以分为四个层次:局部作用域(Local scope)、外部作用域(Enclosing scope)、全局作用域(Global scope)和内置作用域(Built-in scope)。 局部作用域是指当前函数或代码块中的变量作用...

    js作用域链图解ppt

    JavaScript中的作用域链是理解变量查找和闭包的关键概念。作用域链主要涉及到函数执行上下文和全局执行上下文中的作用域。以下是对这个主题的详细解释: 首先,每个函数在创建时,都会有一个内部属性[[scope]],它...

    第四章示例代码__对象的作用域

    在示例代码中,可能会展示如何在不同作用域内创建和使用对象,包括如何在函数内部创建局部对象,如何在类中定义成员对象,以及如何利用闭包保持对变量的访问。通过这些例子,开发者将能更直观地看到作用域规则的实际...

    JavaScript闭包与作用域链实例分析

    JavaScript的闭包与作用域链密不可分,因此本文可以和JavaScript的作用域链相对照分析,一定可以对JavaScript的闭包和作用域链有更深的理解。 下面我们仍然以createComparisonFunction为例进行闭包的分析。 //step1...

Global site tag (gtag.js) - Google Analytics