`
小野马儿
  • 浏览: 15599 次
社区版块
存档分类
最新评论

函数的作用域

 
阅读更多

一,每一个变量都是有作用域的。

1,首先讲一下代码块与作用域:for, if等语句还有function,他们都有一个特点,就是后面有一对{}比如

for(var i = 0; i < items.length; i++){
    //“{”和“}”之间有代码
}

if(some_express){
    //“{”和“}”之间有代码
}

function(param1){
    //“{”和“}”之间有代码
}

 所有{}包起来的代码,都可以称之为 “代码块” , 英文名叫Block。

每个代码块都有一个自己的作用域,作用域决定了变量能否被访问(不论读取变量还是修改变量)。

访问的规则大概是这样的:

[1] 在最上层没有任何{}包裹的作用域为顶层作用域,声明的变量是哪里都可以访问的,如:

var x = 5;
if(x>0){ //可以访问
    x = 6; //可以访问
}

function print_x(){
    console.log(x); //也可以访问
}
 [2] 任何一个代码块,{}之间的代码区域称之为它的作用域,每一对大括号括起来的代码块里声明的变量,只能在这个代码块的作用域里访问,不过在js里是不具备这个能力的。 但是为了建立起正确的思维观,我们还是要讲讲块级作用域。虽然语言不支持,但我们人不要跨越块级作用域,这是一个基本素质,会极大的减少Bug发生率。
if(true) {
    var x = 5;
    console.log(x); //可以访问
}
console.log(x); //其他语言里无法访问,但是在js里可以
 [3] 代码块是有层级的,在一个代码块里写的新的代码块,后者是前者的子作用域
if(true){
    //相对于下面的代码块的父作用域
    var x = 5;
    if(x > 0){
        //子作用域
    }
}
 [4] 子作用域可以访问父作用域的变量,但是父作用域无法访问子作用域的变量
if(true){
    var x = 5;
    if(x > 0){
        var y = "a";
        console.log(x); //可以访问
        x = 6; //也可以访问
    }
    console.log(y); //不应该在这里再访问了。
} 
 [5] 作用域的父级的父级作用域的变量,该作用域里也可以访问,甚至无穷多级父的作用域里的变量都可以被访问,这种无穷多级的父,被称之为祖先
if(true){
    var x = 5;
    if(x > 0){
        console.log(x); //可以访问
        for(var i = 0; i < x; i++){
            console.log(x); //也可以访问
        }
    }
}
 [6] 顶层作用域是所有作用域的祖先
2,函数的作用域
函数比起if,for等代码块有一个显著地不同,就是他可以在参数列表里声明变量
function a(param1, param2){
    //这里就可以使用param1和param2了
}
 在父作用域声明的变量,也可以在函数内被访问
var x = 5;

function a(param1){
    console.log(x); //可以访问到,打印的是5
}
 关于作用域的覆盖问题,当子作用域有变量与父作用域重名的时候,在子作用域里只能访问到子作用域的变量。称之为 覆盖。
var x = 5;

function a(x){
    console.log(x); //这时访问的x就不是父作用域的x了,而是参数x
}

a(6); //打印的是6
console.log(x); //打印的是5
 所以,子作用域的覆盖不会消除父作用域的变量
var x = 5;

function a(x){
    console.log(x); //这时访问的x就不是父作用域的x了,而是参数x
}

a(6); //打印的是6
console.log(x); //打印的是5
 例如:
var x = 5;

function a(x){
    if(x > 0){
        x++;
    }
    console.log(x);
}

a(1);
console.log(x);
 代码的最后一行输出结果是5.
//因为覆盖并不会改变父作用域的变量。
3,要注意一些容易犯的错误:
for(var i = 0; i < 3; i++){
    var result = [];
    result.push(i);
}
console.log(result); //有的初学者以为这里会打印 [0,1,2],实际上会打印[2],因为result是在for里面被定义的, 每次循环都被重新初始化了
 关于覆盖也是容易出错误:
var x = 0;
function fun(){
    console.log(x);
    var x = 1;
    x++;
}

fun();
 我们想先用一下全局变量x,然后再在子作用域里声明一个重名的局部变量x。结果我们会发现console.log()打印出的是 undefined。 因为js虽然是解释执行的,但是在一个作用域里声明的变量在这个作用域里只有一个指向,即便还没有执行到正式声明的哪一行,父级作用域的变量也已经因覆盖无法访问了
二,为了避免一些不必要的错误,我们在书写代码的时候要注意规范命名,养成好的习惯,提高写代码的效率。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics