函数作用域
函数有个隐藏的属性[[scope]],这个属性就是作用域,其存储了运行期上下文的集合。
[[scope]]存储运行期上下文集合,这些集合呈链式关系,就是作用域链。
[[scope]]属性结构
第一个元素 >>> 当前运行函数的 ActivationObject
第二个元素 >>> 当前运行函数父函数的 ActivationObject
第三个元素 >>> 当前运行函数父函数的父函数的 ActivationObject
…………
最后元素 >>> GlobalObject
<script type = "text/javascript">
function a(){
function b(){
function c(){
function d(){
}
d();
}
c();
}
b();
}
function e(){
}
// a 和 e 函数定义时它们的 [[scope]] 属性中只有一个元素,就是 GlobalObject(全局运行时上下文)
//当要执行 a 函数时,a 函数就创建自己的 ActivatonObject(运行时上下文),存储在属性[[scope]]中,并放置到顶端(第1个元素)
//这时 a 函数的[[scope]]属性的内容是
//第一个元素 ActivationObject(a的运行时上下文)
//第二个元素 GlobalObject(全局的运行时上下文)
a();
//当执行 a 函数时,b 函数运行前,b函数属性[[scope]]引用了函数 a 的[[scope]]属性,并且b函数创建自己的 ActivationObject。
//这时 b 函数的[[scope]]属性的内容是
//第一个元素 ActivationObject(b的运行时上下文)
//第二个元素 ActivationObject(a的运行时上下文)
//第三个元素 GlobalObject(全局的运行时上下文)
//当 b 函数执行时,查找变量的顺序是[[scope]]属性,从上往下查找。直到找到第一个符合的停止。
//当 b 函数执行完后,销毁自己创建ActivationObject
//这时 b 函数的[[scope]]属性的内容变为
//第一个元素 ActivationObject(a的运行时上下文)
//第二个元素 GlobalObject(全局的运行时上下文)
//当执行 b 函数时,c 函数运行前,c函数属性[[scope]]引用函数 b 的[[scope]]属性,并且c函数创建自己的 ActivationObject。
//以此类推,直到所有函数执行完毕。
</script>
闭包:
内部函数被返回到外部时,内部函数本身存着父函数的ActivationObject,即使父函数执行完,取消了对 ActivationObject引用,但内部函数依然可以存取父函数变量。这样就产生闭包。闭包会导致原有作用域链不释放,造成内存泄漏。
闭包的作用:实现公有变量(累加器)、缓存(存储结构)、实现封装,属性私有化、模块化开发,防止污染全局变量。
<script type = "text/javascript">
function a(){
var num = 0;
function b(){
num ++;
document.write("num = ",num,"<br/>")
}
return b;
}
var demo = a();
demo();//1
demo();//2
demo();//3
</script>
闭包应用:缓存
<script type = "text/javascript">
function eater(){
var food = [];
var obj = {
eat:function(){
if(food.length < 1){
document.write("There is no food!<br/>");
}
else{
document.write("i am eating " + food[food.length - 1],"<br/>");
food.pop();
}
},
push:function(myFood){
food.push(myFood);
}
}
return obj;
}
var eater1 = eater();
eater1.push("apple");
eater1.push("banana");
eater1.eat();
eater1.push("orange");
eater1.eat();
eater1.push("cake");
eater1.eat();
eater1.eat();
eater1.push("banana");
eater1.eat();
eater1.eat();
</script>
立即执行函数(初始化功能的函数)
应用在只执行一次的函数。只有函数表达式才能被执行符号()执行,函数声明不能被执行。
<script type = "text/javascript">
(function(){document.write("ohohoh!!","<br/>")}());//W3C推荐立即执行函数格式
(function(){document.write("ohohoh!!","<br/>")})();
var x =(function(a,b,c){
return a + b + c;
}(1,2,3))
document.write(x,"<br/>");
var y = function demo(){
document.write("hahaha!!!","<br/>")
}();
//function error(){document.write("ohohoh!!","<br/>");}();函数声明不能被执行
+function error(){document.write("ohohoh!!","<br/>");}();
</script>
立即执行函数与闭包应用
<script type = "text/javascript">
//立即执行函数,闭包保存循环变量 ii 的使用方式。
function test(){
var arr = [];
for (var i = 0; i < 10; i++) {
(function(ii){
arr[ii] = function(){
document.write("i = " + i + " ii = " + ii + "<br/>")
}
}(i))
}
return arr;
}
var myArr = test();
for(var j = 0;j < myArr.length;j++){
myArr[j]();
}
</script>