JavaScript-作用域

129 阅读3分钟

js属于弱类型的语言,所以声明变量的时候不需要指定变量的类型,使用统一的关键字即可。

var x = 18; 
y = "abc";

声明变量和非声明变量

判断方式:是否用var(let const)来修饰。

1.声明变量的作用域限制在其声明位置的上下文中,而非声明变量总是全局的

function x() {
     y = 1; 
     var z = 2;
}
x();
console.log(y); // 打印'1',y为非声明变量-全局.
console.log(z); // 抛出ReferenceError:z未在x外部声明

2.声明变量在任何代码执行前就会声明**(并未定义)**,而非声明变量只有在执行赋值操作的时候才会被定义。

console.log(a1); // 打印'undefined'或''(不同浏览器实现不同)
var a1 = 1;

console.log(a2); // 抛出ReferenceError
a2 = 1;

var hoisting

由于变量声明总是在任意代码执行之前处理的,所以在代码中的任意位置声明变量总是等效于在代码开头声明。这就意味着变量可以在声明之前使用,这个行为叫做变量声明提升(hoisting)。

Java中不可以这样做。

bla = 2;
var bla;

// 可理解为
var bla;
bla = 2;

由于这个原因,我们建议是在作用域的最开始(函数或者全局代码的开头)声明变量,这样可以使变量的作用域变得清晰。

否则,在底部声明的变量也提升到最开始,容易出错。

 var v = "hello";
 def(v);
 function def(){
    alert(v);
    var v = "i love you";
 }
//output:undefined

变量声明关键字

虽然是弱类型语言,但JavaScript还是有三种变量修饰符: const let var,它们的区别在于声明的变量作用域不同。

var

使用var语句声明的变量的作用域:

1.变量在函数内声明时,作用域为当前函数的内部。

2.变量在函数外声明时,作用域为全局。

let

let语句声明一个块级作用域的本地变量:作用域为当前变量最近的{}。

JavaScript对作用域的要求

1..在同一个作用域中用let重复定义一个变量将引起TypeError,而var会进行覆盖上一个变量。

2.不同作用域中存在同名变量时采用就近原则:

当前域存在一个同名变量的声明就使用它,不存在时向上找最近的作用域变量。

在掌握二者的作用域范围后,使用就近原则进行分析即可。

function varTest() {
    var x = 1;
    if (true) {
        // 两个x是在相同作用域中,var会覆盖
        var x = 2; 
		console.log(x); // 2
     }
    console.log(x); // 2
}

function letTest() {
    let x = 1;
    if (true) {
        // 对于let来讲,两个x压根就在不同的作用域,采用就近原则
        let x = 2; 
        console.log(x); // 2
    }
    console.log(x); // 1
}
letTest();

var x = 1;
function varTest() {
    if (true) {
        // 现在两个X的作用域也不同了:第一个X是全局变量,而第二个X则是方法作用域内的变量。
		var x = 2; 
		console.log(x); //2
    }
}
varTest();
console.log(x); // 1   

const

这个声明创建了一个常量,可以在全局作用域或者函数内部声明常量,常量需要被初始化。这就是说,在定义常量的同时必须初始化(这是有意义的,鉴于常量的值在初始化后就不能改变)。

常量拥有块作用域,和使用let定义的变量十分相似。常量的值不能通过再赋值改变,也不能再次声明。

隐式全局变量和外部函数作用域

// x是全局变量
var x = 0;
function f(){
     //y是隐式的全局变量,
    var x = y = 1;	
    console.log(x); //1 此处的x是函数作用域内的变量,不会影响到外部的
}
f();
console.log(x, y); // 0, 1