1、执行环境、作用域链
执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。
每一个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。虽然我们的代码无法访问这个对象,但是解析器在处理数据时会在后台执行它。
全局执行环境是最外围的一个执行环境。根据ECMScript实现所在的宿主环境不同,表示执行环境的对象也不一样。
每一个函数都有自己的执行环境。当执行流进一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将其环境弹出,把控制权返还给之前的执行环境。当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。
测试1:
var color1 = "blue";
function changeColor(){ //局部环境 2级作用域
var color2 = "red";
function swapColor(){ //局部作用域 3级作用域
var color3 = color2;
color2 = color1;
color1 = color3;
}
alert(color1);
alert(color2);
alert(color3);
}
changeColor(); //全局执行环境 1级作用域
结果:输出bule、red、Uncaught ReferenceError: color3 is not defined
环境变量 可以一层一层的向上进行追溯 可以访问它的上级 环境(变量和函数),但是不能向下追溯
测试2:
var color1 = "blue";
function changeColor(){
var color2 = "red";
function swapColor(){
var color3 = color2;
color2 = color1;
color1 = color3;
}
swapColor();
}
alert(color1);
alert(color2);
alert(color3);
changeColor();
结果:输出blue、Uncaught ReferenceError: color2 is not defined
测试3:
//1 执行环境 window对象(最上层的执行环境)
var color1 = "blue";
function changeColor(){ // 每一个函数 都有一个执行环境 (variable obj)
var color2 = "red";
function swapColor(){ // 这个函数 又产生了一个执行环境 (variable obj)
// c3 3级作用域 c2 2级作用域 c1 1级作用域
var color3 = color2;
color2 = color1;
color1 = color3;
//这里可以访问:color1、2、3
alert(color1);
alert(color2);
alert(color3);
}
//这里可以访问color1、color2、但不能访问color3
swapColor();
}
//这里只能访问color1
changeColor(); // 作用域 window 第一个作用环境
结果:输出red、blue、red
2、垃圾收集
离开作用域的值将被自动标记为可以回收,因此将在垃圾收集期间被删除。标记清除是目前主流的垃圾收集算法。这种算法的思想是给当前不使用的值加上标记,然后回收其内存。
在js里,主要有标记方法、引用计数法进行垃圾回收
测试1:
function test(){
var a = 10; //被使用
var b = 20; //被使用
var c;
}
test(); //执行完毕 之后 a、b又被标记了一次 :没有被使用
3、块级作用域
javascript里面没有块级作用域的概念,和C、JAVA等高级语言不同。所以在使用if、for时候要格外的小心。
测试1:
function test(){
for(var i=1;i<=5;i++){
alert(i);
}
alert(i);
}
test();
结果:输出1、2、3、4、5、6
4、javascript模拟高级语言里的块级作用域
在js里()表示立即执行,这个是非常关键的
测试1:
(function(){alert("我直接执行了");})();
结果:输出我直接执行了
测试2:
function test(){
(function(){
for(var i = 1;i <= 5;i++){
alert(i);
}
})();
alert(i);
}
test();
结果:输出1、2、3、4、5、Uncaught ReferenceError: i is not defined
成功模拟了高级语言里的块级作用域,第六个值输出了undefined
5、闭包
一个函数 可以访问另外一个函数作用域中的变量
封闭性,private 起到一个保护变量的作用
测试1:
var name = "xiao A";
var obj = {
name : "xiao B",
getName:function(){
return function(){
return this.name;
}
}
}
alert(obj.getName()());
结果:输出xiao A
测试2:
var name = "xiao A";
var obj = {
name : "xiao B",
getName:function(){
return function(){
return this.name;
}
}
}
var k = obj.getName();
alert(k());
结果:输出xiao A,和上面是等价的
测试3:
var name = "xiao A";
var obj = {
name : "xiao B",
getName:function(){
return function(){
return this.name;
}
}
}
var k = obj.getName();
alert(k());
alert(k);
alert(typeof k);
结果:输出
xiao Afunction(){
return this.name;function
测试4:如果想访问到xiao B
var name = "xiao A";
var obj = {
name : "xiao B",
getName:function(){
// this总是指向调用者
var o = this;
return function(){
return o.name;
}
}
}
alert(obj.getName()());
结果:输出xiao B
测试5:
function f(x){
var temp = x;
return function(x){
temp+=x;
return temp;
}
}
var a = f(10);
alert(a(20));
结果:输出30
测试6:
//1级作用域
function f(x){ //2级作用域
var temp = x;
return function(x){ //3级作用域
temp+=x;
return temp;
}
}
var a = f(10);
alert(a(20));
alert(a(30));
alert(a(40));
结果:输出30、60、100
总结:
本篇主要讲述了js里的执行环境、作用域及作用域链、垃圾收集的2种方法、块级作用域、闭包
执行环境:分为了全局和局部的执行环境,全局的执行环境的执行对象时window,而局部的执行环境的执行对象是隐藏的一个variable obj对象
作用域链即在执行函数寻找所谓的变量的时候是通过变量所处的作用域范围一层一层往上追溯的,这里注意的是向上追溯,不能向下追溯
垃圾回收主要是标记清除法,和Java语言是类似的;另外一种是计数法,通过count的计数加减,当count等于0的时候回收。
js没有块级作用域,主要注意的是区别其它高级语言的块级作用域。
闭包就是函数存在嵌套,一个函数可以访问另外一个函数作用域中的变量