JavaScript解析机制——深入理解变量提升

1.预解析概念

在当前作用域下,js运行之前,会把带有var和function关键字的事先声明,并在内存中安排好。(这个过程也可以理解为变量提升)然后再从上到下执行js语句。预解析只会发生在通过var定义的变量和function上。

2.var声明的变量

使用var声明的变量预解析:告诉解析器知道有这个名字的存在并默认将该变量赋值undefined ,如下:

console.log(x);  //undefined
var x = 5;

变量x虽然是在console.log后面定义的,但是使用var申明的x会提前保存在内存中,并赋值undefined ,然后再从上往下执行js语句 。它的执行顺序类似于下面的结构:

var x;
console.log(x);  //undefined
x = 5;

先声明了x ,x没有定义赋值为undefined ,输出的结果自然为undefined 。然后再给x赋值为5。

需要注意的是,如果变量声明没有使用var ,不存在变量提升的。如下:

console.log(x);  //error: x is not defined
x = 5;

x没有使用var声明,所以报错找不到x。

3.functin声明的函数

使用function声明函数的预解析:先告诉解析器这个函数名的存在,然后在告诉解析器这个函数名的函数体是什么 。如下:

console.log(f); 
function f() {
    console.log("xx");
}

声明函数会把整个函数都提升到最前面 ,所以浏览器中结果会输出整个函数,结果如下:

function f() {
    console.log("xx");
}

如果在一个函数作用域中声明一个变量 ,那么它也会提升到函数作用域的最上面,如下:

var x = 5;
function f() {
    console.log(x);   //undefined
    var x = 2;
}
f();

以上虽然全局作用域声明了一个变量x ,但是函数里面也声明了一个变量x ,所以会先查找函数里面是否有变量x,如果有的话就不会再全局下查找了。函数里面的变量x会被提升到函数作用域的最前面 ,并且赋值为undefined,所以输出结果为undefined ,类似于如下结构:

var x = 5;
function f() {
    var x;
    console.log(x);   //undefined
    x = 2;
}
f();

函数的参数也可以理解为函数作用域的变量 ,如下:

var x = 5;
function f(x) {
    console.log(x);   //undefined
}
f();
console.log(x);   //5

为函数f传递一个形参x ,由于函数在调用时没有传递实参 (也就是说变量x没有赋值) ,所以为undefined 。而在全局下输出x自然在全局下查找变量x ,结果为5。

4.变量或函数覆盖

如果在同一个作用域下声明两个相同的变量或者函数,那么后一个会覆盖前一个。如下:

var x = 5;
var x = 10;
console.log(x);   //10
function f() {
    console.log("xx");
}
function f() {
    console.log("yy");
}
f();   //yy

如果声明的函数与变量名字相同 ,那又会怎么覆盖呢?可以看如下例子:

var f = 5;
function f() {
    console.log("xx");
}
f();   //error: f is not a function

JavaScript中 ,函数的预解析优先级是要高于变量的预解析的。无论函数在什么位置声明 ,都优选把整个函数提升到最前面。所以上面的例子中 ,虽然函数f是在变量f下面定义的 ,但是在预解析时先解析函数f ,然后再解析变量f ,后面的变量f会把前面的函数f覆盖,最后f为5 为数值类型 ,所以调用f时报错 ,f不是一个函数。

需要注意的是 ,如果变量m定义后没有赋值 ,那么函数就不会被覆盖了,如下:

var f;
function f() {
    console.log("xx");
}
f();   //xx

掌握以上知识,我们看下面的例子 :

console.log(x);   //function x() {console.log(5);}
var x = 2;
console.log(x);   //2
function x() {
    console.log(3);
}
console.log(x);   //2
var x = 3;
console.log(x);   //3
function x() {
    console.log(5);
}
console.log(x);   //3
x();   error: x is not a function

以上例子,两个函数x优先提升 ,所以第二个函数x覆盖第一个函数x。然后两个变量x提升,由于变量x提升后为undefined,所以第二个函数没有被覆盖 ,第一个输出x结果为第二个函数function x(){console.log(5);}。随后x被赋值为2 ,所以第二个输出x结果为2。因为第一个函数x已经被提升到前面去了,所以第三个输出x结果还是2。随后为x赋值为3,所以第四,第五输出x结果为3。最后调用x,x因为是数值类型,所以会报错x不是一个函数。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值