原生js作用域以及变量提升和函数提升的理解

在ES5的时候,只存在两种作用域:函数作用域和全局作用域;ES6出现后,增加了块级作用域

首先通过代码讲下ES5中的函数作用域和全局作用域理解:

<script type="text/javascript">
  var a = 0;
  func();
  function func()
  {
    var b = 1;
    console.log(a); //0 函数作用域中访问全局变量
    console.log(b); //1
  }
  console.log(b); //报错 全局作用域中访问func函数作用域中的局部变量
</script>

上面代码中,有两种作用域。全局变量a存在于全局作用域中,而变量b则存在于函数func()所在的函数作用域中,也就是局部变量。 
1. 当我们在函数作用域中访问变量a时,在func函数这个作用域中找不到变量a时,会继续往全局作用域找,因此在函数作用域中访问变量a时实际上是访问的全局变量a,所以console的结果是0。 
2. 如果在函数func中访问不存在的变量c,在func这个函数作用域中找不到,然后继续往全局作用域找,还是找不到变量c,然后就报错。
3. 当我们在全局作用域访问func函数中的局部变量b时,由于已经处在全局这个大作用域中,再全局作用域中找不到变量b,而全局作用域又叫顶级作用域,因此无法继续往上查找,结果就是直接报错。

可以将全局作用域和函数作用域之间的关系理解为父与子,func函数作用存在于全局作用域中,相当于儿子。当儿子没有某个东西的时候,就会找父亲要,如果父亲也没有,那就报错,而父亲是不会找儿子要东西的,这个东西就是js中的变量。js在查找变量时,都是从下级作用域往上级作用域查找的,如果一直到顶级作用域(全局作用域)都没找到,则报错。

 

可以通过下面的图解,再详细的看下函数作用域和全局作用域的调用方式:

<script type="text/javascript">
  var i = 1;
  function fn1()
  {
    var i = 5;
    var j = 20
    function fn2()
    {
      var i = 10;
      function fn3()
      {
        var j = 15;
        console.log(i); //10
      }
      fn3();
      console.log(i); //10
      console.log(j); //20
    }
    fn2();
  }
  fn1();
  console.log(i); //1
</script>

实际调用如下图所示:

ES6出现后,增加了块级作用域

A: 在es5片段中的代码:

var a = 0;
if(a < 10)
{
    a++;
    var b = a;
}
console.log(b); //1  b是全局变量。处于全局作用域,会成为全局对象window对象的属性

理解:以上代码,虽然b是在if代码块中定义的,但由于ES5只有全局作用域和函数作用域,没有块级作用域,而b变量不是在函数中定义的,所以b只能是全局变量。

B: es6代码片段:

let a = 0; //注意:使用'let声明的全局变量不会成为window对象的属性
if(a < 10)
{
    a++;
    let b = a;
}
console.log(b); //报错 b是if代码块中的变量,只在'if'代码块{}中生效。处于块级作用域。

ES6中{ }会形成一个块级作用域,所以上面代码的b处于if这个块作用域中,不属于全局作用域。

 

变量提升的理解:

在ES6之前,JavaScript没有块级作用域(一对花括号{}即为一个块级作用域),只有全局作用域和函数作用域。变量提升即将变量声明提升到它所在作用域的最开始的部分。上个简单的例子如:

1

2

3

4

5

6

7

8

9

10

console.log(global); // undefined

var global = 'global';

console.log(global); // global

 

function fn () {

  console.log(a); // undefined

  var a = 'aaa';

  console.log(a); // aaa

}

fn();

  之所以会是以上的打印结果,是由于js的变量提升,实际上上面的代码是按照以下来执行的:

1

2

3

4

5

6

7

8

9

10

11

12

var global; // 变量提升,全局作用域范围内,此时只是声明,并没有赋值

console.log(global); // undefined

global = 'global'// 此时才赋值

console.log(global); // 打印出global

 

function fn () {

  var a; // 变量提升,函数作用域范围内

  console.log(a);

  a = 'aaa';

  console.log(a);

}

fn();

 

函数提升的理解:

js中创建函数有两种方式:函数声明式和函数字面量式。只有函数声明才存在函数提升!如:

1

2

3

4

console.log(f1); // function f1() {}   

console.log(f2); // undefined  

function f1() {}

var f2 = function() {}

  只所以会有以上的打印结果,是由于js中的函数提升导致代码实际上是按照以下来执行的:

1

2

3

function f1() {} // 函数提升,整个代码块提升到文件的最开始<br>    

console.log(f1);   

console.log(f2);   

var f2 = function() {}

  

结语:基本上就是这样,要熟练掌握的话可以多做些练习,test:

1

2

3

4

console.log(f1()); 

console.log(f2);   

function f1() {console.log('aa')}

var f2 = function() {}

 

1

2

3

4

5

6

(function() {

  console.log(a);

  a = 'aaa';

  var a = 'bbb';

  console.log(a);

})();

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值