js作用域

1.什么是作用域?

作用域就是变量与函数的可访问范围,即作用域控制着函数与变量的可见性和生命周期

1.全局作用域

任何地方都能访问到的对象拥有全局作用域

1.1.函数外面定义的变量拥有全局作用域,全局变量拥有全局作用域,网页中所有脚本和函数均可使用。全局变量在页面关闭后销毁

var n = 2;
function fn(){
    var a = 1;
    returrn a;  
}

console.log(fn());   //1
console.log(n);  // 2
console.log(a);   //报错error

1.2.未定义直接赋值的变量自动声明为全局变量拥有全局作用域

var n = 2;
function fn(){
    a = 1;
    returrn a;  
}

console.log(fn());   //1
console.log(n);  // 2
console.log(a);   //1

1.3.window对象的属性拥有全局作用域

HTML中,全局变量是window对象,所有数据变量都属于window对象

//此处可使用 window.carName
 
function myFunction() {
    carName = "Volvo";
}

2.局部作用域

局部作用域一般只在固定的代码片段内能访问到,最常见的例如函数内部,所以也称为函数作用域

变量在函数内声明,变量为局部作用域

局部变量:只能在函数内访问

// 此处不能调用 carName 变量
function myFunction() {
    var carName = "Volvo";
    // 函数内可调用 carName 变量
}

因局部变量只作用于函数内,所以不同的函数内可以使用相同名称的变量名

局部变量在函数开始执行时创建,函数执行完成后局部变量会自动销毁

3.ES6的块级作用域

ES5只有全局作用域和函数作用域,没有块级作用域,会带来以下问题

3.1.变量提升导致内层变量可能会覆盖外层变量

var  i = 5;
function func(){
    console.log(i);
    if(true){
          var i = 6;       
    }
}
func();   //undefined

3.2.用来计数的循环变量泄露为全局变量

for(var i = 0;i<10;i++){
   console.log(i)
}
console.log(i);  //10

ES6引入了块级作用域,明确允许在块级作用域中申明函数,let和const命令都涉及块级作用域

块级作用域允许声明函数只在使用大括号的情况下成立,如果未使用大括号报错

if (true) {

function func1() {} // 不报错

}

if (true)

function func2() {} // 报错

作用域链

当声明一个函数时,局部作用域一级一级向上包起来,就是作用域链

1.当执行函数时,总是先从函数内部寻找局部变量

2.如果内部找不到(函数的局部作用域没有),则会像创建函数的作用域(声明函数的作用域)寻找,依次向上

var a = 1;
function fn(){
    var a = 10;
    function fn1(){
        var a = 20;
        console.log(a);  //20 
     }
    function fn2(){
       console.log(a);  //10
    }
    fn1();
    fn2();
}      
fn();
console.log(a);  //1  

当执行fn1()时,创建函数fn1的执行环境,并将该对象置于链表开头,然后将fn的调用对象放在第二位,最后是全局对象,作用域链的链表结构是fn1>fn>window,从链表的开头寻找变量a,即从fn1函数内部找变量a,找到了结果是20.

同样,当执行fn2()时,创建函数fn2的执行环境,并将该对象置于链表开头,然后将fn的调用对象放在第二位,最后是全局对象,作用域链的链表结构是fn2>fn>window,从链表的开头寻找变量a,即从fn2函数内部找变量a,找不到,于是从fn内部找变量a,找到了结果是10

最后再最外层打印变量a,直接从变量a的作用域即全局作用域内寻找,结果为1

4.闭包

简单来说,闭包就是函数外部能读取到函数内部的变量

优点:闭包可以形成独立的空间,永久的保存局部变量

缺点:保存中间值的状态缺点是造成内存泄漏,因为闭包中的局部变量永远不会被回收

function f1(){
     var n = 999;
     nAdd = function(){
       n += 1;
    }
    function f2(){
           console.log(n)
    }
    return f2;
}  

var result = f1();
result();  //999
nAdd();  //执行 n+=1;
result();  //1000  

 

posted @ 2019-05-23 15:31  一顿操作猛如虎  阅读(1014)  评论(0编辑  收藏  举报