js作用域和变量提升

作用域

作用域的分类

  • 全局作用域
    在一个js脚本中,最外层的作用域就是全局作用域,在此范围内声明的任何变量都会是全局变量,可以在程序的任意位置访问

  • 局部作用域

    • 函数作用域
    var locales = {
    school: function() {          // 这里的school(学校)是局部作用域
      var student = "公众号:搞前端的半夏";
    
      var apartment = function() {   //这里的apartment(宿舍楼)也是局部作用域
        var room = function() {  // 这里的room依然是局部作用域
          console.log(student);  // 公众号:搞前端的半夏
        };
    
        room();
      };
    
      apartment();
    }
    };
    
    locales.school();    //公众号:搞前端的半夏
    

    我们想找到student,是怎么查找的呢,首先我们在他的宿舍查找,没有找到,然后会往上一层宿舍楼进行查找,宿舍楼没有找到,然后在往学校查找,最终找到了student。

    • 代码块作用域
      在代码块(if, for,while等等)中使用let和const声明变量,let和const会为这个代码块创建一个新的块级作用域。
    function f(n) {
    if (true) {
      const msg = '你好';
      let name = n;
      console.log(msg + " " + name);     //公众号-搞前端的半夏
    }
    console.log(msg + " " + name);      //报错  msg is not defined
    }
    
    f('公众号-搞前端的半夏');    
    

    通过let和const在块级作用域外是无法被访问的。

    function f(n) {
    if (true) {
      var msg = '你好';
      var name = n;
      console.log(msg + " " + name);     //公众号-搞前端的半夏
    }
    console.log(msg + " " + name);        //公众号-搞前端的半夏
    }
    

    当我们使用var关键字时,变量在整个函数作用域都是可访问的
    在 JavaScript 中,可以在多层嵌套范围内指定同名变量。在这种情况下,局部变量优先于全局变量。如果你声明了一个同名的局部变量和一个全局变量,当你在函数或块中使用它时,局部变量将优先。

JavaScript 解释器从当时正在执行的最内层范围开始,一直持续到找到第一个匹配项,无论外层级别中是否存在其他同名变量。
var test = "我是全局";

function testScope() {
  var test = "我是局部";
  console.log (test);     
}

testScope();           // output: 我是局部
console.log(test);     // output: 我是全局

即使名称相同,局部变量在函数执行后也不会覆盖全局变量testScope()。

var test = "我是全局";

function testScope() {
  test = "我是局部";

  console.log(test);     
}

console.log(test);     // output: 我是全局

testScope();           // output: 我是局部

console.log(test);     // output: 我是局部 

这一次,局部变量test覆盖了同名的全局变量。当我们在testScope()函数内部运行代码时,全局变量被重新分配。如果一个局部变量在没有首先用关键字声明的情况下被赋值var,它就变成了一个全局变量。为避免此类情况,应始终在使用局部变量之前声明它们。在函数中使用关键字声明的任何变量var都是局部变量。

总结

  • var 变量是函数作用域
  • let and const 变量是块级作用域
  • 使用var关键字声明的全局作用域变量属于window对象。
    使用let关键字声明的全局作用域变量不属于window对象。
  • var关键字定义的变量可以先使用后声明。
    let关键字定义的变量需要先声明再使用。
    const关键字定义的常量,声明时必须进行初始化,且初始化后不可再修改。

变量提升

var a = 1

function fn(){
   console.log(a)
   var a = 2
}
fn() //undefined

这个代码相当于

var a = 1

function fn(){
   var a    //undefined
   console.log(a)
   a = 2
}
fn() //undefined

变量声明提升

函数提升

function f() {
  x();
  
  function x() {
    console.log(1);
  }
}

f();

这个代码等价于

function f() {

  function x() {
    console.log(1);
  }
  
  x();
}

f();

扩展

var fn = function(){}和function fn(){}的区别:前者为变量提升,后者为函数提升。
fn1()  //fn1
fn2()   //fn2 is not function
function fn1() {
      console.log("fn1")
}
var fn2 = function() {
      console.log("fn2")
}

f();
如果是用变量提升来声明函数,如果在此前调用该函数,此时的函数对象并没有创建,变量fn2赋值为undefined,所以浏览器不能识别,把它当做函数来调用,所以最后报错。
在js中,函数优先级最高

被覆盖的不是函数fn,而是var fn =3;

console.log(fn)
function fn() {
      console.log("hello world")
}
var fn = 1

结果
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值