作用域

当某一个执行环境的程序执行完毕后,该环境会被销毁,保存在其中的变量和函数也跟着销毁

全局执行环境当应用程序退出时才会被销毁(例如关闭网页)

全局执行环境被认为是window对象。因为所欲全局变量和函数都是作为window对象的属性和方法创建的

每一个函数都有一个自己的环境,当执行到某个函数时,该函数的环境就进入一个环境栈中,当函数执行完毕后,则环境栈会弹出该环境

当程序在一个环境中执行时,会建立一个作用域链,是为了保证有权访问该环境的所有有序变量和函数

在一个环境内部定义的变量或者函数不能影响到外部的变量或者函数,只作用于该环境内部

例如:

var hi = "hello";
function no(){
    var hi = "hi";
    console.log(hi);

    function go(){
        var abc = "go";
            hi = "abc";
        console.log(abc);
        console.log(hi)
    }
    go();

}
no();
cosole.log(abc);
console.log(hi);

有三个环境,全局环境,abc的局部环境,go的局部环境


自由变量

当在某一个作用域上要使用某个变量,但是没有在该作用域中声明,需要到其他作用域中找到这个变量,而这个变量为自由变量,例如:

var a = 100;

funotion c(){
    var b = 1;
    console.log(a + b); // a为自由变量
}
c();

取a的值要到另一个作用域中获取,要到创建这个被执行函数的作用域中(函数c是在全局作用域中被创建的)取值,所以要到创建函数c的作用域中获取到a的值,如果在创建的作用域中也没有找到该变量,那么会一直向上找,一直找到全局作用域,还是没有找到就抛出错误,而这个沿着作用域一直向上级寻找的机制叫作用域链

延长作用域链

只有两种情况可以延长:with语句和try-catch语句的catch块,例如:

function abc(){
    var a = "/index.html";
    with(location){
        var url = href + a;
    }
        return url;
}
var o = abc()
console.log(o);

父对象的所有变量,对子对象都是可见的,但是子对象的所有变量,父对象是不可见的


闭包

闭包的本质就是在一个函数内部建立另一个函数

闭包的特性:

函数嵌套函数

在函数内部可以引用函数外部的变量或者参数

变量和参数不会被垃圾回收机制清理

例如:

function a(){
    var b = 'abc';
    return function(){
        return b;
    }
}
var c = a();
console.log(c());

a()返回的值是一个匿名函数,这个函数在a()的作用域内部,所以可以获取a()作用域中的变量b的值,然后将这个值作为返回值赋值给全局作用域中的变量c

var a = 10;
var b = function(c){
    if(c>a){
        console.log(c);
    }
}
void function(abc){
    var a = 100;
    abc(20);

}(b);

这是通过作用域链的特性,让局部作用域外部也可以获取到局部作用域内部的变量

因为在局部作用域中可以获取到全局作用域的变量,而局部作用域通过向上返回值来达到传递值的目的


this

每一个作用域中都绑定了一个特别的关键字:this

在全局作用域下,this表示为window对象,例如:

var name = "this";
console.log(this.name);
console.log(window.name);

改变this的值:

call(),apply(),bind()

例如:

var a = function(){
    console.log(this);
}
a.call('hi');