又来复习概念了,这次因为理解“执行环境”、“作用域”、“this指向的对象” 、“闭包函数”概念出现了混乱。网上每个点都有很多不同说法,看的很晕,所以自己翻了一下《js高程》,再次理解了一遍,记录一下,方便以后忘记再次理解。
执行环境。
概念:每个执行环境都有一个与之关联的变量对象,环境中定义的变量和函数都保存在这个对象中。我们无法访问它,后台解析器处理数据时会用到它。
运行原理:除了全局环境,每个函数都有自己的执行环境。当前函数运行时,会把当前函数的环境推入“环境栈”中,函数执行完毕后,“环境栈”将其推出,把控制权返回给之前的环境,接而推入下一个函数执行环境。
销毁时机:某个执行环境中的所有代码执行完毕,环境被销毁,保存在其中的所有变量和函数也都被销毁(全局环境直到应用程序关闭时才会销毁,比如关闭网页)。
作用域。
概念:当代码在一个环境中执行时,会创建变量对象的一个作用域链,用来保证对执行环境内的变量和函数进行有序的访问。
作用域链:先是当前执行环境的变量对象,下一个变量是外部环境,下下一个变量是外外部环境,直到全局环境为止。
活动对象:如果当前环境是函数,则变量对象是其活动对象(最开始只包含arguments对象,另外这个对象在全局环境中是不存在arguments的)。
访问规则:内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量。
一个函数被调用时,会创建一个执行环境 以及 一个相应的作用域链。然后,使用arguments和其它命名参数的值来初始化函数的活动对象。
例子
在创建compare()函数时,会创建一个预先包含全局变量对象的作用域链,这个作用域链被保存在内部的[[Scope]]属性中。
当调用compare()函数时,会为函数创建一个执行环境,复制[[Scope]]属性中的对象成为当前环境的作用域链的变量对象,之后往这个作用域链中推入当前函数的活动对象(arguments、v1、v2)作为变量对象。
所以compare函数的作用域链中包含两个变量对象:本地活动对象和全局变量对象。
当compare函数执行完毕,本地活动对象就随环境一起被销毁,内存被释放,内存中仅保存全局作用域。
但是闭包的情况又有所不同。
闭包概念:有权访问另一个函数作用域中的变量的函数(函数a内嵌套函数b,b函数就算闭包)。
闭包函数例子
a函数初始化时,其作用域链中有全局变量对象。
a函数调用时( var b = a('age') ),其作用域中增加了本地活动对象(arguments、o1)。
a函数执行完毕,返回匿名函数。a函数的环境和作用域链被销毁,但其活动对象不被销毁(因为还在被匿名函数引用)。
匿名函数初始化,其作用域链中有全局变量对象、a函数活动对象。
匿名函数调用( b({age:10},{age:11}) ),其作用域链中有全局变量对象、a函数活动对象,本地活动对象(arguments、q1、q2)。
匿名函数结束调用,a函数的活动对象和匿名函数的变量对象全部被销毁。
注意:因为全局变量b中保存着对匿名函数的引用,其实匿名函数的变量对象和a的活动对象并不会被销毁,导致内存泄漏。
解决:var b = null。
再来看一个例子
函数a返回了一个函数数组res。结果是res的10个函数都是 "return 10"。这是为什么?
这10个函数都是匿名函数,他们在初始化时,作用域链中包含 “函数a的活动对象、全局变量对象”。那么其“return i”的i来自函数a的活动对象。当res被返回时,i已经变成10,各个函数的作用域链中的a的活动对象中的i也都是10。
这是因为,如果外部函数有1个变量的值反复被更新,对于该变量,闭包函数只能取得最后一个值。
那我们让它正常的返回1-10,该怎么做?
解决方法
我们不要让i来自a函数的活动对象,因为它最后的值是10。我们再在中间加一层函数b(i){...}并接受i的值作为活动对象,此时闭包函数初始化时的作用域链包含“函数b的活动对象,函数a的活动对象、全局变量对象”。而函数b的活动对象i,没有进行变化,闭包就能取得i的值为1-10。
关于this对象记住两点:
1、this对象是函数在运行时基于函数的执行环境绑定的。
2、我们直到函数在被调用时,都会自动取得两个特殊变量this和arguments。函数内在搜索这两个变量时只会搜索到自己的活动对象,不会像其它普通变量一样通过作用域向上去搜索。
例子1
b()其实就是window.b(),执行环境是window对象,所以this对象绑定的是window对象,也就返回了全局对象‘111’。
例子2
首先obj.getA()函数的执行环境是obj,所以getA函数的this对象也就指向obj。
obj.getA()返回的匿名函数,该函数的执行环境是全局环境,所以this指向全局对象,也就返回"111"。
你可能会误以为匿名函数的this对象会根据作用域往上查找,其实并不会。
例子3
h函数是自己执行的,相当于执行环境是全局环境。
例子4
obj.getA()的执行环境是obj,函数内的this也就指向obj。
把obj.get函数取出来后,在外部执行,执行环境就是全局环境,函数内的this也就指向全局变量。
例子5
o.b.fn(),函数fn的执行环境是b对象,但b对象中并无a变量,所以返回undefined。
当this碰到return时:如果返回值是一个对象(不包括null),那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。
当碰到return时











网友评论