变量声明和变量提升

JS代码的执行过程分为两个阶段:
1.预解析过程:找到所有的变量和函数声明,提升到作用域的最前面
2.执行过程

1.作用域

变量起作用的范围就是变量的作用域。在JavaScript中唯一能产生作用域的东西是函数。
1)块级作用域:使用代码块限定的作用域。JavaScript中没有块级作用域
2)词法作用域:在代码写好的那一刻,变量的作用域就已经确定了。和词法作用域相对的是动态作用域,JS中没有

使用规则:

  • 函数允许访问函数外的变量
  • 整个代码结构中只有函数可以限定作用域
  • 作用域规则首先使用提升规则分析
  • 如果当前作用域中有了该变量,就不再考虑外面的同名变量
2.关于变量声明
  • 设置值的时候,也是访问变量;获取值的时候也是访问变量
  • 并不是在函数内部写了变量,这个变量就属于这个函数的作用域;而是必须使用var来声明变量,这个变量才会属于这个作用域
  • 函数在声明的时候里面的代码不会执行,只有在调用的时候,代码才会执行
  • 声明函数时的函数名,其实也是一个变量名,可以通过这个变量名来给其赋值
3.用var、let、const 声明变量时的区别

1)用 var 声明的变量作用域是它当前的执行上下文,它可以是嵌套的函数,也可以是声明在任何函数外的变量。而 let 和 const 是块级作用域,意味着他们只能在最近的一组花括号(function、if-else 代码块或 for 循环)中访问。

if(true){
    var bar = "bar";
    let baz = "baz";
    const qux = "qux";
}
console.log(bar);//bar
console.log(baz);//baz is not defined
console.log(qux);//qux is not defined

2)var 会使变量提升,这意味着变量可以在声明之前使用。而 let 和 const 不会使变量提升,提前使用会报错。

console.log(foo);//undefined 
//这里注意var声明的变量可以提升但是赋值不可以,所以是undefined
var foo = "foo";

console.log(baz);//ReferenceError
let baz = "baz";

console.log(bar);//ReferenceError
const bar = "bar";

3)用 var 重复声明变量,不会报错,但是 let 和 const 这样做会报错。

var foo = "foo";
var foo = "bar";
console.log(foo); //bar
let baz = "baz";
let baz = "qux";//SyntaxError

4)let 和 const 的区别在于:let 允许多次赋值,而 const 只允许一次。

//不会报错
let foo = "foo";
foo = "bar";
//会报错
const baz = "baz";
baz = "qux";
4.变量提升和函数提升

在分析代码的时候,首先应将以var声明变量名和以function开头的函数进行提升,再去执行代码的具体执行过程。
1.变量的提升是分作用域的

function foo(){
    var num = 123;
    console.log(num);
}
foo();//123
console.log(num);//num is not defined

这里需要注意的是:
undefined 是定义了没有赋值
is not defined 是没有定义

2.函数表达式中函数的声明不会被提升,但是变量会被提升

var scope = "global";
foo();
function foo(){
    console.log(scope);//undefined
    var scope = "local";
    console.log(scope);//local
}

//提升后的代码为
var scope;
function foo(){
    var scope;
    console.log(scope);//undefoned
    scope = "loacl";
    console.log(scope);//local
}
foo();
scope = "global";

3.函数同名:预处理的时候,会将两个函数全部提升,但是后面的函数会将前面的函数覆盖

var m = 1;
function add(n){
    return n = n + 1;
}
y = add(m);
function add(n){
    return n = n + 3;
}
z = add(m);
console.log(y);//4
console.log(z);//4

function add() { } 定义的函数会优先解析,而不是顺序解析。因此整个过程中,首先解析两个 add 函数,但是由于两个函数同名,所以后者会覆盖前者;然后顺序解析其余的代码。y = add(m);z = add(m); 语句调用的都是第二个 add 函数,所以返回的值都是4。

4.变量与函数同名:在提升的时候,如果有变量和函数同名,则会忽略掉变量,只提升函数

console.log(foo); //foo(){ }
function foo(){}
var foo = 2;
console.log(foo); //2

//提升后的代码
function foo(){};
alert(foo);
foo=2;
alert(foo);

5.变量提升只会将变量和函数提升到当前作用域的最上方

//例1
if(a in window){
    var a = 10;
}
console.log(a);//10

//提升之后的代码
var a;
if(a in window){
    a = 10;
}
cosnole.log(a);//10

//例2
function f1(){
    if(a in window){
        var a = 10;
    }
    console.log(a);
}
f1();//undefined

//提升后的代码
function f1(){
    var a;
    if(a in window){
        a = 10;
    }
    console.log(a);
}
f1();//undefined

猜你喜欢

转载自blog.csdn.net/cathence/article/details/80516673