js块级作用域和let、const、var的区别

js块级作用域和let、const、var的区别

  1. 块作用域

js中作用域有:全局作用域、函数作用域。没有块作用域的概念。ES6中新增了块级作用域。块级作用域由{ }包括if语句和for语句里面的{ }也属于块作用域。
我们都知道在javascript里面是没有块级作用域的,而ES6添加了块级作用域,会计作用能改变什么呢?为什么会新增块级作用域呢?那就要先知道ES5没有块级作用域时出现了哪些问题。

在if或者for循环中声明变量会泄露成全局变量
for (var i=0;i<=5;i++){
  console.log("hello");
}
  console.log(i); //6
内层变量可能会覆盖外层变量
var ss=new Date()
function f() {
      console.log(ss);
      if(true){
        var ss="hello"
 }
f() //undifined

不管最后是否执行if语句,都会输出undifined,因为ss会提升到函数顶部,因此覆盖了外部的ss变量。而let和const命令,它们所声明的变量只在所在的代码块内有效,即为js添加了块作用域。

允许块级作用域任意嵌套
{{{let temp="hello world"}}}
外层作用域无法读取到内层作用域的变量
{{{
	{let temp='hello world'}
	console.log(temp)
}}}  
内层作用域可以定义与外层作用域同名的变量
{{{
  let temp="111"
  {let temp="2222"}
}}}

函数本身的作用域在其所在的块级作用域内

function f() {console.log("111");}
   (function () {
     console.log(f);
     if(false) {function f() {console.log("222");}}
     console.log(f);}
     f()
   ())

这里我是这样理解的,ES5中虽然存在函数声明式提升,但是如果函数的声明放在了条件语句中且条件为false的时候,虽然进行了函数提升将其顶到了作用的最顶层,此时第一个console.log(f)执行结果为undefined,但是到执行false的时候,由于条件为false,所以函数并没有被声明,因此第二个console.log(f)执行结果也为undefined,在作用域内执行函数作用内f()时会报错,因为f()时没有被声明的。而在ES6中执行的话则会执行最外层的f()输出111。

在ES5,因为没有块级作用域,获得广泛运用的是立即执行函数(即闭包),现在ES6增加了块级作用域,那么立即执行函数就不再必要了.ES6以前变量的作用域是函数范围,有时在函数内局部需要一些临时变量,因为没有块级作用域,所以就会将局部代码封装到IIEF(立即执行函数)中,这样达到了想要的效果又不引入多余的临时变量。而块作用域引入后,IIEF当然就不必要了!临时变量被封装在IIEF中,就不会污染上层函数;而有块级作用域,就不用封装成IIEF,直接放到一个块级中就好。更简单的说法是,立即执行匿名函数的目的是建立一个块级作用域,那么现在已经有了真正的块级作用域,所以立即执行匿名函数就不需要了。

//立即执行函数
(function(){
	var temp="hello world"
})
//块级作用域
{
	var temp="hello world"
}
  1. var let和const的区别

    js中作用域有:全局作用域、函数作用域。没有块作用域的概念。ES6中新增了块级作用域。块级作用域由{ }包括if语句和for语句里面的{ }也属于块作用域。
    我们都知道在javascript里面是没有块级作用域的,而ES6添加了块级作用域,会计作用能改变什么呢?为什么会新增块级作用域呢?那就要先知道ES5没有块级作用域时出现了哪些问题。
在if或者for循环中声明变量会泄露成全局变量
for (var i=0;i<=5;i++){
  console.log("hello");
}
  console.log(i); //6
内层变量可能会覆盖外层变量
var ss=new Date()
function f() {
      console.log(ss);
      if(true){
        var ss="hello"
 }
f() //undifined

不管最后是否执行if语句,都会输出undifined,因为ss会提升到函数顶部,因此覆盖了外部的ss变量。而let和const命令,它们所声明的变量只在所在的代码块内有效,即为js添加了块作用域。

允许块级作用域任意嵌套
{{{let temp="hello world"}}}
外层作用域无法读取到内层作用域的变量
{{{
	{let temp='hello world'}
	console.log(temp)
}}}  
内层作用域可以定义与外层作用域同名的变量
{{{
  let temp="111"
  {let temp="2222"}
}}}

函数本身的作用域在其所在的块级作用域内

function f() {console.log("111");}
   (function () {
     console.log(f);
     if(false) {function f() {console.log("222");}}
     console.log(f);}
     f()
   ())

这里我是这样理解的,ES5中虽然存在函数声明式提升,但是如果函数的声明放在了条件语句中且条件为false的时候,虽然进行了函数提升将其顶到了作用的最顶层,此时第一个console.log(f)执行结果为undefined,但是到执行false的时候,由于条件为false,所以函数并没有被声明,因此第二个console.log(f)执行结果也为undefined,在作用域内执行函数作用内f()时会报错,因为f()时没有被声明的。而在ES6中执行的话则会执行最外层的f()输出111。

在ES5,因为没有块级作用域,获得广泛运用的是立即执行函数(即闭包),现在ES6增加了块级作用域,那么立即执行函数就不再必要了.ES6以前变量的作用域是函数范围,有时在函数内局部需要一些临时变量,因为没有块级作用域,所以就会将局部代码封装到IIEF(立即执行函数)中,这样达到了想要的效果又不引入多余的临时变量。而块作用域引入后,IIEF当然就不必要了!临时变量被封装在IIEF中,就不会污染上层函数;而有块级作用域,就不用封装成IIEF,直接放到一个块级中就好。更简单的说法是,立即执行匿名函数的目的是建立一个块级作用域,那么现在已经有了真正的块级作用域,所以立即执行匿名函数就不需要了。

//立即执行函数
(function(){
	var temp="hello world"
})
//块级作用域
{
	var temp="hello world"
}

2. let、const、var的区别

  1. var定义的变量,没有块的概念,可以跨块访问,不能跨函数访问,由变量提升
  2. let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问,无变量提升
  3. const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域块里访问,而且不能修改,无变量提升,不可以重复注明,注意:const常量,指的是常量对应的内存地址不能改变,而不是对应的值不能改变,这一点要搞清楚,把所有应用类型的数据设置为常量,其内部的值是可以改变的 记住.
    let声明的变量只在块级作用域内有效
function f() {
      if(true){
        let i=6
        console.log(i);//6
      }
      console.log(i); //报错 i is not defined
    }
    f()

不存在变量提升,而是"绑定"暂时性死区

function f() {
      if(true){
        console.log(i);//报错 let没有变量提升
         let i=6
      }
    }
    f()

在let声明变量前,使用该变量,它是会报错的,而不是像var那样会"变量提升". 准确来说let没有"变量提升"的特性这样说是不正确的,应该说它提升了,但是在ES6中规定了在let声明变量前不能使用该变量.

var test=1
    function f() {
      console.log(test); //报错
      let test=2
    }
    f()

如果let声明的变量没有变量提升,应该输出1外部的test的结果才对,而它缺是报错,只是规定了不能在其声明之前使用而已,所以称let的这一特性为"暂时性死区",且这一特性,仅仅针对块级作用域有效(let const)

let使用的经典案例:let命令代替闭包功能

 //使用闭包实现给数组中的每个元素赋值为方法
 var arr=[]
    for(var i=0;i<10;i++){
      arr[i]=(function (i) {
        return function f() {
          return i
        }
      })(i);
    }
   console.log(arr[3]()+"  "+arr[1]());
  
  //let实现闭包原理
   var arr=[]
    for(let i=0;i<10;i++){
      arr[i]=function(){
      	return i
      }
    }
   console.log(arr[3]()+"  "+arr[1]());

剩下const命令了!

const和let的使用规范一样,与之不同的是:

const声明的是一个常量,且这个常量必须赋值(即必须初始化),否则会报错

function f() {
      const PI
      PI=3.14
      console.log(PI); //报错 Missing initializer in const(即没有初始化)
    }
    f()
posted @ 2020-12-11 12:10  轻风格走一走  阅读(335)  评论(0编辑  收藏  举报