DLX Dev Everything Engineer

c,java,JavaScript的作用域语义差异

2020-06-06

作用域是指计算机语言中变量、函数、类等起作用的范围。

函数作用域

以C语言为例:


/*
scope.c
测试作用域。
 */
#include <stdio.h>

int a = 1;

void fun()
{
    a = 2;
    //b = 3;   //出错,不知道b是谁
    int a = 3; //允许声明一个同名的变量吗?
    int b = a; //这里的a是哪个?
    printf("in fun: a=%d b=%d \n", a, b);
}

int b = 4; //b的作用域从这里开始

int main(int argc, char **argv){
    printf("main--1: a=%d b=%d \n", a, b);

    fun();
    printf("main--2: a=%d b=%d \n", a, b);

    //用本地变量覆盖全局变量
    int a = 5;
    int b = 5;
    printf("main--3: a=%d b=%d \n", a, b);

    //测试块作用域
    if (a > 0){
        int b = 3; //允许在块里覆盖外面的变量
        printf("main--4: a=%d b=%d \n", a, b);
    }
    else{
        int b = 4; //跟if块里的b是两个不同的变量
        printf("main--5: a=%d b=%d \n", a, b);
    }

    printf("main--6: a=%d b=%d \n", a, b);
}

这段代码编译后运行结果:

main--1: a=1 b=4 
in fun: a=3 b=3 
main--2: a=2 b=4 
main--3: a=5 b=5 
main--4: a=5 b=3 
main--6: a=5 b=5 

块作用域

另外,C 语言里还有块作用域的概念,就是用花括号包围的语句,if 和 else 后面就跟着这样的语句块。块作用域的特征跟函数作用域的特征相似,都可以访问外部变量,也可以用本地变量覆盖掉外部变量。

但是java的块作用域和C的块作用域有些不同。


/**
 * Scope.java
 * 测试Java的作用域
 */
public class ScopeTest{

    public static void main(String args[]){
        int a = 1;
        int b = 2;

        if (a > 0){
            //int b = 3; //不允许声明与外部变量同名的变量
            int c = 3;
        }
        else{
            int c = 4;   //允许声明另一个c,各有各的作用域
        }
        
        int c = 5;  //这里也可以声明一个新的c
    }
}

Java 的块作用域跟 C 语言的块作用域是不同的,它不允许块作用域里的变量覆盖外部变量。那么和 C、Java 写起来很像的 JavaScript 呢?来看一看下面这段测试 JavaScript 作用域的代码:


/**
 * Scope.js
 * 测试JavaScript的作用域
 */
var a = 5;
var b = 5;
console.log("1: a=%d b=%d", a, b);

if (a > 0) {
    a = 4;
    console.log("2: a=%d b=%d", a, b);
    var b = 3; //看似声明了一个新变量,其实还是引用的外部变量
    console.log("3: a=%d b=%d", a, b);
}
else {
    var b = 4;
    console.log("4: a=%d b=%d", a, b);
}

console.log("5: a=%d b=%d", a, b);

for (var b = 0; b< 2; b++){  //这里是否能声明一个新变量,用于for循环?
    console.log("6-%d: a=%d b=%d",b, a, b);
}

console.log("7: a=%d b=%d", a, b);

运行结果:


1: a=5 b=5
2: a=4 b=5
3: a=4 b=3
5: a=4 b=3
6-0: a=4 b=0
6-1: a=4 b=1
7: a=4 b=2

JavaScript 是没有块作用域的。我们在块里和 for 语句试图重新定义变量 b,语法上是允许的,但我们每次用到的其实是同一个变量

参考:

  1. ^极客时间,宮文学,《编译原理之美》

Comments

Content