js(作用域+预解析+变量提升+函数声明提升)团团转了

882 阅读2分钟

作用域?

作用域是啥子了
它指的是你的变量和函数运行到某个地方的代码处能否被访问到(即变量起作用的区域)
为什么需要作用域?为什么要限制变量的访问性而非全部暴露到公共域下讷?
这个是人家计算机科学中最基本的概念和理念,隔离性为了职责明确,你只能刚好访问到你需要的所有东西不多也不少
附带的
它带来了,模块化,命名空间的好处,使得代码更易阅读,更易维护,可以说作用域是很多语言支持的一个特性
词法作用域 指的是一个变量,你可以通过变量名引用之,而不发生引用错误,本质上是静态作用域,

作用域类型?

全局作用域
不定义在任何函数内的变量、或函数都位于全局作用域下
函数作用域
任何定义在函数内的变量、或函数都处于函数作用域下,这些变量无法在函数以外被引用到
块级作用域 es6之前没有这个东西,就是说,定义在{}大括号及for(i=0;i<10;i++){...}循环结构中的变量统统跑到了全局作用域下,es6通过let和const恢复了这个问题,即块级作用域
外层作用域 全局作用域是最外层的作用域,外层作用域下的变量及函数可以在内层作用域中被访问获取到 内存作用域
可以访问到外层作用域的变量,可以访问自身的变量,但是不能被外层作用域引用

js运行阶段

js的运行阶段分为

预编译阶段(预解析)
执行阶段
变量提升和函数声明提升 就是在这个阶段提升
在预编译阶段 js引擎会做一些事情 即读取变量的定义 并确定其作用域的生效范围

js变量定义

使用var关键字定义变量 并未赋值的情况下 该变量的值未undefined
变量作用域
全局变量的作用域遍布全局
局部变量的作用域仅在于函数内部
函数内部的同名变量 参数其优先级高于全局同名变量(即函数内部变量于外部变量重名)

js作用域:变量起作用的区域

在JS中 var和function定义的变量是根据 函数划分作用域
定义在局部作用域中的变量就是局部变量 局部变量仅限于函数内部使用 出了函数就被销毁
定义在函数外部的变量就是全局变量 全局变量可以在任何地方使用
当全局变量和局部变量同名时,全局变量不会作用于局部变量的变量
在局部环境中优先使用局部变量
定义变量时省略了var关键字 则变量会成为全局变量

var和let-const区别?

var定义的变量可以变量提升 (也叫域解析 域加载 ...)在声明变量之前可调用 为undefined
var定义的变量会成为window属性
只被函数限制作用域
变量声明提升 来看一个demo代码如下

var name = '常东东';
function say(){
    console.log(name);      //输出:undefined
    var name = '收购腾讯';
    console.log(name);      //输出:'收购腾讯'
}
say(); 
//上述代码解析:say函数执行第一次打印name时并未打印全局的name('常东东'),而是打印局部的name(undefined),
//这是因为在预编译阶段,say函数内部进行了变量声明提升,
//提升后的执行效果如下             
var name = '常东东';
function say(){
var name;              //变量name声明提升至作用域顶部,但未赋值,故为undefined
console.log(name);     //存在局部name,则无视全局name
name = '收购腾讯';     //变量赋值保持原位
console.log(name);     //输出:'收购腾讯'
}
say(); 

函数声明提升

1函数声明
2函数表达式

            //函数声明 (声明式函数 具名函数)
say();      //输出 "常东东"
function say(){
    console.log("常东东")
}
            //函数表达式 (赋值式函数 赋值给一个变量)
say();      //报错 say is not function
var say = function(){
    console.log("常东东")
}
//原因在于,通过函数声明的方式,该函数声明(包括定义)会被提升至作用域的顶部,
//表达式的创建方式则只提升了变量say至作用域的顶部,此时的say其值为undefined,
//调用say()自然报错“say不是一个方法”。
var say = function(){
  console.log('1');
};
function say(){
  console.log('2');
};
say();       //输出"1"          
             //预编译阶段进行变量声明提升和函数声明提升后,
             //上述代码执行效果等同于
var say;             //变量声明提升
function say(){      //函数声明提升
  console.log('2');
}
say = function(){    //变量赋值保持原位执行,say函数被覆盖
  console.log('1');
};
say();               //输出'1'

函数声明提升,会将函数的声明和定义全都提升至作用域顶部。
变量声明提升,只提升声明部分(未赋值状态),赋值部分保持原位置不动。

函数声明提升的优先级要高于变量声明提升。

console.log(say); //输出:[Function: say] 是一个函数体
function say(){
  console.log('1');
};
var say = '2';
console.log(say);        //输出'2"
                         //本例中声明的函数和变量同名都是say,且函数声明在先,变量声明在后,
                         //按理说第一次打印say值预期会是undefined 然而结果是[Function: say]。
                         //预编译阶段进行变量声明提升和函数声明提升后,上述代码执行效果等同于
var say = function (){   //函数声明(包括定义)提升
  console.log('1');
};
var say;                 //只是声明,并不会覆盖say的值
console.log(say);        //故输出:[Function: say]
say = '2';               //此时say会被覆盖
console.log(say);        //输出'2'
//!!同名情况下,函数声明提升优先级要高于变量声明提升,
//! 且提升后该函数声明定义不会被提升后的同名变量声明所覆盖  
//但是会被后续顺序执行的同名变量赋值所覆盖

仅供参考了