`
kanny87929
  • 浏览: 17510 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Javascript的作用域,闭包的真正含义

阅读更多

javascript函数作用域分两个阶段
一个叫创建时阶段
一个叫运行时阶段

定义1:
所谓“创建时阶段”就是一个函数被以某种语法定义出来的时候,
并且此函数被创建在一个运行时阶段的作用域中时,此函数才为闭包状态,才能有自己的“创建时阶段”的作用域。

(在这里要说的是,所有被压入函数作用域链的值,都是对“可变对象”的引用,当所有这个“可变对象”的引用都断开的时候,这个“可变对象”才可能被垃圾回收,从内存中删去)

当浏览器的一个窗口被打开时,就自动开启了一个最顶级的"运行时阶段的作用域",
我们一般叫它“全局作用域”,所有在这个“全局作用域”中以某种语法定义出来
的函数就自动进入了“创建时阶段”,就有了自己“创建时阶段”的作用域。
并且自己“创建时阶段”的作用域链上自动插入,
创建自己的“运行时阶段”的“可变对象”的引用,
并且逐级插入。。。直道插入最后一个“可变对象”(就是最顶级的“运行时阶段”所产生的,一般我们叫它‘Global Object’).

定义2:
所谓“运行时阶段”就是一个函数被()操作符标识为要运行的时候,
(提示所有被()操作符标识为运行的函数都要在一个“运行时阶段”的作用域中才能被运行,如果不在则无法被运行)
此时,函数本身会创建一个内部对象,叫“运行期上下文”对象,
“运行期上下文对象”有自己的[[scope]]属性,此属性将copy此函数“创建时阶段”的[[scope]]属性的值,也就是“创建时阶段的作用域链”做为“运行时阶段的作用域链”的最初形态,有了这个最初形态以后,运行期上下文将组织聚集函数内部的所有标识符等等属性为一个对象,这个对象叫做"可变对象",然后将这个对象的引用压入自己作用域链的第一个位置。



下面做代码实例解析

var a = function() {
 var i = 0;
 var b = function() {
   alert(i);
 };
 return b;

}


以上代码,此时a函数被以某种语法定义出来
a函数被创建在最顶级的“运行时阶段”的作用域链中,
此时a函数才被允许有自己的“创建时阶段”的作用域链。。。
此时a函数的作用域链上插入了创建自己的“运行时阶段”的“可变对象”的引用,
就是对"Global Object可变对象"的引用

此时b函数以某种语法定义出来,并且是被定义在a函数内部,
但由于a函数的作用域才处于“创建时阶段”
如果b函数要有自己的作用域就必须符合定义1
但很可惜不符合。。。因为b函数没有被创建在一个“运行时阶段”的作用域中,而是被创建在一个“创建时阶段”的作用域中,不满足定义1,所有b函数此时还没有作用域。

当执行以下这一行代码时

var b = a();


a函数被()操作符标识为要运行的时候,
此时,a函数本身会创建一个内部对象,叫“a函数运行期上下文-01”的对象,
(这里提示一下,每当a函数被运行的时候都会产生一个"a函数运行期上下文-XX"对象)
“a函数运行期上下文对象”有自己的[[scope]]属性,此属性将copy a函数“创建时阶段”的[[scope]]属性的值,也就是“创建时阶段的作用域链”做为“运行时阶段的作用域链”的最初形态,有了这个最初形态以后,运行期上下文将组织聚集函数内部的所有标识符等等属性为一个对象,这个对象叫做"可变对象",然后将这个对象的引用压入自己作用域链的第一个位置。

此时b函数终于符合定义1了,它被创建在一个“运行时阶段”的作用域链中,于是b函数有了自己的“创建时阶段”的作用域,并且“创建时阶段”的作用域链上插入a的可变对象的引用和全局可变对象的引用,此时b函数处于闭包状态。

当执行以下这两行代码时

var b = a();
b();


当第一行代码执行完毕的时候,也就是当a函数执行完毕的时候,“a函数的运行期上下文对象”也被销毁,所以此上下文创建的作用域链也销毁,所以对"a的可变对象"的引用断开了,也就是说,如果“a的可变对象”如果没有其他引用的话随时会被垃圾回收释放内存,但是上面说了b函数处于闭包状态了,b函数的“创建时阶段”的作用域链已经有了一个对"a的可变对象"的引用,也就是说不会被垃圾回收无法释放内存,直到b函数执行完毕后“a的可变对象”和“b的可变对象”才都断开了引用,才会被垃圾回收释放内存。



读了还不懂作用域和闭包的同学,自己买一款豆腐去死吧


总结一下:

任何一个函数当它拥有自己的“创建时阶段”的作用域时,它的“创建时作用域链”上
都持有对它外部每一层函数的可变对象的引用...从而导致闭包状态

函数嵌套的越深其需要的内存空间越大,因为外部每一层函数的可变对象都被其引用,导致无法释放
如果内部第99层函数用到了内部第3层函数的某一个变量,将导致其作用域链的大规模搜索,从而导致性能问题。。。



我这篇文章不一定对,因为还有一个问题没有得到正解
就是如果内部函数没有用到外部函数的数据的时候,是否会对外部函数的可变对象持有引用

我的文章里说的观点是不管有没有用到外部函数的数据,都对外部函数的可变对象持有引用。

这个问题就变的很复杂了
是因为用了外部的函数的数据会形成了引用外部函数的可变对象
还是因为持有外部函数的可变对象的引用才能访问外部函数的数据。
分享到:
评论
1 楼 指甲刀X 2012-08-09  
关于最后的问题,个人认为不管内部函数是否访问外层定义的变量,都持有外层变量的引用,因为在内部函数声明时,外层变量所属的VO都被加在内部函数的[[scope]]属性上,这里是不会管内部函数是否要访问的。

相关推荐

    005课-继承作用域闭包.rar

    从文件名"005课-继承作用域闭包"来看,课程可能包含以下内容: 1. **继承的介绍**:讲解JavaScript中的原型链继承和类继承,包括如何定义构造函数、原型链的工作原理、以及如何通过`extends`关键字进行类的继承。 ...

    详解JavaScript作用域 闭包

    JavaScript中的作用域和闭包是理解JavaScript高级特性的重要概念,对于编写高效、可维护的代码至关重要。在这篇文章中,我们将深入探讨这两个主题。 首先,我们要明白JavaScript的作用域。JavaScript的作用域决定了...

    深入理解javascript原型和闭包

    深入理解javascript原型和闭包(01)——一切都是对象 深入理解javascript原型和闭包(02)——函数和对象的关系

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

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

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

    JavaScript作用域是编程中至关重要的概念,它规定了变量和函数的可见性及生命周期。JavaScript主要有两种作用域:全局作用域和局部作用域。 全局作用域是指在代码的任何位置都可以访问的变量或函数,这通常包括在最...

    JS的作用域与闭包

    闭包是JavaScript中一个高级概念,它允许一个函数记住并访问它外部作用域中的变量,即使该函数在其外部作用域之外执行也是如此。 ##### 1. 闭包的定义 闭包是由函数和与其相关的引用环境组合而成的实体,这个环境...

    现代JavaScript高级教程:深入作用域、闭包及DOM操作

    内容概要:本书《现代JavaScript高级教程》全面涵盖了JavaScript的高级特性和技术,从基础到进阶逐步讲解,特别强调了作用域、闭包、DOM操作等核心概念。书中提供了丰富的示例代码和实际应用场景,帮助读者深入理解...

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

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

    Web前端面试题目JavaScript(作用域,原型。原型链,闭包,封装函数).txt

    前端面试题,包含JavaScript的闭包,作用域,原型,原型链,上下文环境以及DOM,BOM封装函数深度克隆,以及一些常见的·JS问题,试题简单但是容易混淆,作为前端工程师必考题

    JavaScript作用域原理

    JavaScript作用域是编程中至关重要的概念,它定义了变量、函数和对象的可见性和生命周期。在JavaScript中,作用域主要分为两种类型:全局作用域和局部作用域。此外,随着ES6的引入,块级作用域和函数作用域也变得...

    05-JavaScript作用域.pdf

    JavaScript作用域是指在JavaScript代码中,变量、常量、对象和函数能够访问的范围。在编程中,变量和函数的使用都受到作用域的限制,决定了它们能够在哪些代码块中被引用。作用域有助于防止变量命名冲突,也使得程序...

    深入理解JavaScript作用域共12页.pdf.zip

    JavaScript作用域是编程中至关重要的概念,尤其是在JavaScript这种动态类型的脚本语言中。它规定了变量、函数以及其它标识符的可见性和生命周期,是代码组织和管理的关键元素。本资料"深入理解JavaScript作用域共12...

    JavaScript 中的闭包是指内部函数可以访问外部函数作用域中的变量

    在JavaScript中,闭包(Closure)是一个极其关键的概念,它使得内部函数能够访问到其外部函数的作用域内的变量,即使外部函数已经执行完毕。这一特性是基于JavaScript的函数作用域规则以及函数本身可以作为值进行...

    深入理解javascript作用域和闭包

    JavaScript中的作用域和闭包是理解其核心概念的关键。作用域决定了变量的可见性和生命周期,而闭包则是JavaScript中一种独特且强大的特性,允许函数访问并操作其外部作用域的变量,即使在其外部作用域已经结束的情况...

    scope-chains-closures, Javascript作用域链和闭包 workshop.zip

    scope-chains-closures, Javascript作用域链和闭包 workshop 范围链和闭包 workshop正在启动$ npm install -g scope-chains-closures$ scope-chains-closures # or, shorter: sccjs使用箭头

    理解_JavaScript_闭包

    本文结合 ECMA 262 规范详解了闭包的内部工作机制,让 JavaScript 编程人员对闭包的理解从“嵌套的函数”深入到“标识符解析、执行环境和作用域链”等等 JavaScript 对象背后的运行机制当中,真正领会到闭包的实质。

    JavaScript作用域示例详解_.docx

    JavaScript作用域是编程中至关重要的概念,它规定了变量和函数的可见性和生命周期。了解JavaScript作用域对于编写高效、安全的代码至关重要。本篇将详细解释JavaScript作用域的几个核心特性,包括无块级作用域、函数...

    javascript里的闭包是什么 什么是闭包.zip

    JavaScript中的闭包是一种重要的编程概念,它涉及到函数、作用域和变量持久化等多个核心知识点。闭包的本质是函数能够访问并操作其外部作用域内的变量,即使在其外部作用域已经结束之后仍然能保持对这些变量的访问。...

Global site tag (gtag.js) - Google Analytics