深入理解JavaScript中的预解析(2)

在私有作用域中,代码执行的时候,遇到了一个变量,首先需要确定它是否为私有变量,如果是私有变量,那么和外面的任何东西都没有关系,如果不是私有的,则往当前作用域的上级作用域进行查找,如果上级作用域也没有则继续查找,一直查找到window为止,这就是作用域链。

当函数执行的时候,首先会形成一个新的私有作用域,然后按照如下的步骤执行:

如果有形参,先给形参赋值;

进行私有作用域中的预解析;

私有作用域中的代码从上到下执行

函数形成一个新的私有的作用域,保护了里面的私有变量不受外界的干扰(外面修改不了私有的,私有的也修改不了外面的),这也就是闭包的概念。

console.log(total); var total = 0; function func(num1, num2) { console.log(total); var total = num1 + num2; console.log(total); } func(100 , 200); console.log(total);

以上代码执行的时候,第一次输出total的时候会输出undefined(因为预解析),当执行func(100,200)的时候,会执行函数体里的内容,此时func函数会形成一个新的私有作用域,按照之前描述的步骤:

先给形参num1、num2赋值,分别为100、200;

func中的代码进行预解析;

执行func中的代码

因为在func函数内进行了预解析,所以func函数里面的total变量会被预解析,在函数内第一次输出total的时候,会输出undefined,接着为total赋值了,第二次输出total的时候就输出300。 因为函数体内有var声明的变量total,函数体内的输出total并不是全局作用域中的total。

最后一次输出total的时候,输出0,这里输出的是全局作用域中的total。

console.log(total); var total = 0; function func(num1, num2) { console.log(total); total = num1 + num2; console.log(total); } func(100 , 200); console.log(total);

将代码作小小的变形之后,func函数体内的total并没有使用var声明,所以total不是私有的,会到全局作用域中寻找total,也就说说这里出现的所有total其实都是全局作用域下的。

四、 全局作用域下带var和不带var的区别

在全局作用域中声明变量带var可以进行预解析,所以在赋值的前面执行不会报错;声明变量的时候不带var的时候,不能进行预解析,所以在赋值的前面执行会报错。

console.log(num1); var num1 = 12; console.log(num2); num2 = 12;

深入理解JavaScript中的预解析

输出结果.png

num2 = 12; 相当于给window增加了一个num2的属性名,属性值是12;

var num1 = 12; 相当于给全局作用域增加了一个全局变量num1,但是不仅如此,它也相当于给window增加了一个属性名num,属性值是12;

问题:在私有作用域中出现一个变量,不是私有的,则往上级作用域进行查找,上级没有则继续向上查找,一直找到window为止,如果window也没有呢?

获取值:console.log(total); --> 报错 Uncaught ReferenceError: total is not defined

设置值:total= 100; --> 相当于给window增加了一个属性名total,属性值是100

function fn() { // console.log(total); // Uncaught ReferenceError: total is not defined total = 100; } fn(); console.log(total);

注意:JS中,如果在不进行任何特殊处理的情况下,上面的代码报错,下面的代码都不再执行了

五、 预解析中的一些变态机制

5.1 不管条件是否成立,都要把带var的进行提前的声明

if (!('num' in window)) { var num = 12; } console.log(num); // undefined

JavaScript进行预解析的时候,会忽略所有if条件,因为在ES6之前并没有块级作用域的概念。本例中会先将num预解析,而预解析会将该变量添加到window中,作为window的一个属性。那么 'num' in window 就返回true,取反之后为false,这时代码执行不会进入if块里面,num也就没有被赋值,最后console.log(num)输出为undefined。

5.2 只预解析“=”左边的,右边的是指,不参与预解析

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwjzsj.html