js块级作用域和let、const、var的区别
js块级作用域和let、const、var的区别
-
块作用域
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"
}
-
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的区别
- var定义的变量,没有块的概念,可以跨块访问,不能跨函数访问,由变量提升
- let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问,无变量提升
- 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()