js的作用域和变量提升

一、var 、let 和const

  • var :具有声明提升。通过 var 关键词声明的变量没有块作用域。在块 {} 内声明的变量也可以从块之外进行访问(只有在function中声明的变量才是函数作用域,即使是在if、for、while中声明的任然具有全局作用域)
  • let: 没有声明提升。块级作用域,在块 {} 内声明的变量无法从块外进行访问
  • const:没有声明提升,一旦定义就无法修改。
重复定义修改值声明提升块级作用域定义循环变量
var可以可以严格来说不支持(function中可以)可以
let不可以可以支持可以
const不可以不可以(除数组和对象)支持不可以

二、变量提升

什么是变量提升

当栈内存(作用域)形成, JS代码自上而下执行之前,浏览器首先会把所有带var/function关键字的进行提前声明或者定义,这种预先处理机制称之为变量提升。
变量提升阶段,var只声明,而function声明和赋值都会完成
也即,var 定义的变量的声明会提升到当前作用域前面,而对于函数,如果函数没执行的话存储的还只是字符串而已。
例如:

console.log(a); // undefined
console.log(fn); // fn(){var b = 2}
console.log(b); // Uncaught ReferenceError: b is not defined
var a = 1;
function fn() {
    var b = 2;
};
  • 变量提升只发生在当前作用域中,开始加载页面的时候只对全局作用域下的进行变量提升,此时函数作用域如果没执行的话存储的还只是字符串而已

只有在私有作用域中用var和function声明的变量和形参两种才是私有变量,其他都是全局变量。剩下的都不是私有的变量,都需要基于作用域链的机制向上查找。

var a = 12,
  b = 13,
  c = 14;
function fn(a) {
  console.log(a, b, c); 
  var b = c = a = 20;
  console.log(a, b, c); 
}
fn(a);
console.log(a, b, c); 

输出:在这里插入图片描述

  • 全局作用域中,声明并赋值了a=12,b=13,c=14

  • 执行函数fn(a),函数的参数是属于函数内部变量,外部无法访问到,即使与外部变量同名;它们也是两个不同的变量。因此a是函数体内部的参数,而传入的a是值传递

  • var b=c=a=20 相当于var b=20;c=20;a=20 ,其中变量b在函数作用域中会进行声明提升。所以函数内部第一行输出为12,undefined,14。此处12为传入的a ,14为全局作用域中的c

  • 函数第二句,由于c是在全局作用域中的c,所以设置c=20会改变全局作用域中的c。所以最后一句中输出为,12,13,20

  • 所有末定义直接赋值的变量自动声明为拥有全局作用域

function outFun2() {
    value1= "未定义直接赋值的变量";
    var value2= "内层变量2";
}
outFun2();
console.log(value1); //未定义直接赋值的变量
console.log(value2); //value2not defined  内层变量2是局部作用域,函数以外访问不到他

如果在函数中定义变量时,如果不添加var关键字, 这个变量是一个全局变量

条件判断下的变量提升

在当前作用域下,不管条件是否成立都要进行变量提升。

  • function和var一样,不管条件是否成立,都只是先声明,没有定义。
console.log(a); // undefined
console.log(b); // undefined
if (false) {
  var a = 1;
  function b() {
    console.log("1");
  }
}
console.log(a); // undefined
console.log(b); // undefined
console.log(fn); //undefined
if (true) {
  console.log(fn); // function fn() { console.log(1) }
  function fn() {
    console.log(1);
  }
}
console.log(fn); // function fn() { console.log(1) }

在ES6中基于let/const等方式创建的变量或者函数都不存在变量提升机制
在相同的作用域中,let不能声明相同名字的变量

暂时性死区

在块级域中访问的变量:

  • 如果有定义:则此块级作用域中使用此变量
  • 如果没有定义:则此级域向上级域查找此变量
let y=0;
{
console.log(y) //Uncaught ReferenceError: Cannot access 'y' before initialization
//y变量没有变量提升,所以此处找不到y,报错(此现象称为:暂时性死区)
let y = 6
}

只针对let和const命令,只要块级作用域内存在let和const命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。
由于var不受块级作用域影响,即使在里面定义也会提升到外部作用域

变量提升和函数提升

var\ function 申明变量,会被提升到作用域的顶部实现声明;
function 申明的变量提升到顶部 如果在非块级作用域范围同时赋值也在顶部, 如果在块级作用域范围,赋值在块级作用域范围的顶部;
var 申明的变量提升到顶部 但是赋值还是在原地

函数提升时,如果存在同名参数,会被函数体覆盖。而如果函数体内存在多个同名的函数声明,会采用最后一个。(也即,函数提升优于变量提升)

function demo(){
    console.log(a);
    var a = 1;
    var a = function(){
        console.log('111');
    }
    function a(){
        console.log('222');
    }
}
demo();

输出:
function a(){ console.log('222'); }
function demo(a){
    console.log(a);//function a(){ console.log('222'); }
    var a = 1;
    function a(){
        console.log('222');
    }
    console.log(a);//1
}
demo(2);

此段参考链接

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值