对于js中的作用域链理解(读书笔记)
图片中的水印是之前微信订阅号‘奋斗吧代码菌’的水印,现已改同博客名:‘码上猿梦’
学习笔记:
//javaScript作用域:
//首先声明一点,js中没有块级作用域,
比如java中for循环中for(int i = 0; i < arr.length; i++){}中的变量i只能在for循环的大括号内部能访问,
//但是在js中,for(var i = 0; i < arr.length; i++){},i的作用域是包含了这个for循环的函数的作用域,或者是全局作用域.
1.全局作用域
(1).最外层函数和定义在最外层函数外面的变量具有全局作用域:
(2).没有使用var关键字声明变量
上面的代码等价于下面的代码:(没有使用var关键字声明的a自动变为全局变量)
//2.局部作用域
//与全局作用域相反,局部作用域就是声明定义在函数内部的变量或者函数,他们拥有局部作用域,也叫函数作用域,
//这些变量也叫局部变量,这些变量只能在声明定义他们的函数里面访问,
//作用域链:之前学过java, 目前在自学c#和javaScript, 学js才发现在js中真的是万物皆对象: 比在java和c#中更加彻底. C#中的委托将函数名作为对象当成参数传递, 但是java中没有这样的. js中所有的东西都是对象, 函数也是对象, 它具有属性和方法, ( 在java中函数也可以说是方法, 但在js中这样说函数比较恰当,因为函数也是具有方法的. )
//函数和其他对象一样, 拥有可以通过代码访问的属性和一系列仅供js引擎访问的内部属性, 其中有一个内部属性就是作用域链 [[scope]] , 这个内部属性包含了函数被创建时函数作用域中所有对象 ( 函数里面的函数也是对象 ) 的集合, 这个集合被称为函数的作用域链, 它决定了哪些数据能够被这个函数访问. 每个函数都会有这样一个作用域链, 这样一来就会有很多个不同作用域链,
[[scope]] 里面存放的只是一个地址, 也就是Scope chain的地址,[[scope]]指向了Scope chain,Scope chain是一个链表结构,里面存放着各种函数作用域,其中也包括全局作用域,
//程序还没有执行的时候,这个链表的最顶端存放的是全局作用域,比如这段代码:
当函数被创建的时候,它的作用域链就会填入一个全局对象,这个全局对象包含了所有的全局变量,(只列举了部分变量)
如下图:
//如果开始执行add函数,
1 var total = add(5, 10);
//那么这个链表的最顶端一定是当前正在执行的函数的函数作用域(是函数作用域,不是作用域链),全局作用域自然在第二层了(其实在这里我在想,这里的链表是不是栈,这点我没有想明白,留一个疑问吧,以后再思考)
//补充一点:当执行流进入一个函数时,也就是一个函数要被执行时,会创建一个"运行时期上下文(execution context)"的执行环境,这也是一个内部对象, 这个运行时期上下文也是一个作用域链, 也是包含着该函数作用域中所有的对象, 运行时期上下文作用域链是由之前这个函数的作用域链初始化的, 然后js引擎又会去创建一个活动对象(Active Object),这个活动对象包含了函数运行期所有的局部变量,参数以及this等变量,
如下图:
//这个活动对象用于标识符的解析,也就是当你要使用一个变量时,活动对象会去它的作用域链中的一个个函数作用域去遍历寻找该变量的标识符,如果找到了就使用这个标识符对应的变量,
如果没有找到,那就向下遍历另一个函数作用域,直到找到为止,但是如果一直遍历到了全局作用域都没有找到和该标识符的定义,那就好吧,我给你报错.
(而且每个标识符都要经历这个遍历寻找的过程,所以尽量少使用全局变量,而应该多使用局部变量,有一个好的经验法则就是:如果一个跨作用域的对象被使用了一次以上,那就把它存储在局部作用域里再使用,这样也能减少代码量,但最重要的是提高了程序的性能.比如document这个全局变量,)
笔记参考自梦想天空的博客, 其中例子均为手敲, 一一验证过。
博客地址:http://www.cnblogs.com/lhb25/archive/2011/09/06/javascript-scope-chain.html