一 、ES6-块级作用域
1、作用域的含义
javascript中的作用域说的是变量的可访问性和可见性。也就是整个程序过程中哪些部分可以访问这个变量,即变量或者是函数起作用的区域。
2、作用域的类型
javascript中有三种作用域:
- 1、全局作用域
- 2、函数作用域
- 3、块级作用域
1、全局作用域
全局作用域:在script标签内,在函数外的区域。在全局作用域内定义的变量是全局变量,全局变量在任何地方都能访问到。
var greeting = "hello world"
function greet () {
console.log(greeting)
}
greet() // 打印'hello world'
2、函数作用域
函数作用域也叫局部作用域,在js里面,只有函数才能形成的作用域。在函数内部定义的变量,只有在函数内部才能访问,不能在函数以外去访问。
function greet () {
var greeting = 'hello world';
console.log(greeting)
}
greet() // hello world
console.log(greeting) // 报错:Uncaught ReferenceError: greeting is not defined
3、块级作用域
ES6 引入了let 和 const 关键字,和var 关键字不同,在大括号中使用let 和 const 声明的变量存在于块级作用域中。在大括号之外不能访问这些变量。
{
let greeting = 'hello world'
var lang = 'English'
console.log(greeting)
}
console.log(lang) // English
console.log(greeting) // 报错:Uncaught ReferenceError: greeting is not defined
作用域嵌套
像函数可以在一个函数内部声明另一个函数,作用域也可以嵌套在另一个作用域中。
var name = 'Peter'
function greet() {
var greeting = 'hello'
{
let lang = 'English'
console.log(`${lang}: ${greeting} ${name}`)
}
}
greet ()
在这里有三层作用域,首先第一层是块级作用域,第二层是函数作用域,第三层作用域是全局作用域。
词法作用域
词法作用域就是在你写代码时将变量和块作用域写在哪里来决定,也就是词法作用域是静态的作用域,在你书写代码时就确定了
let number = 42
function printNumber() {
console.log(number)
}
function log() {
let number = 54
printNumer()
}
log() // 42
3、作用域链
当在Javascript中使用一个变量的时候,首先Javascript引擎会尝试在当前作用域下去寻找该变量,如果没有找到,再到它的上层作用域寻找,以此类推直到找到该变量。如果找到全局作用域中仍然没有找到该变量,它就会报错。
let foo = 'foo'
function bar () {
let bar = 'bar'
console.log(bar) // bar
console.log(foo) // foo
number = 42
console.log(number) // 42
}
bar()
二、let 与 const 用法
let
用来声明变量,所声明的变量只能在let
命令所在的代码块内有效
const
用来声明常量,就是指针不可以改变的变量,它所声明的常量也只能在const
命令所在的代码块中生效。
1、let 用法
- let 声明的变量只在变量声明时所在的代码块有效
{
let a = 10;
var b = 1;
}
a // ReferenceError: a is not defined.
b // 1
- 不存在变量提升现象
var 命令会发生‘变量提升’现象 ,即变量可以在声明之前使用,值为underfined;但let所声明的变量一定要在声明后使用,否则报错
// var
console.log(foo) // underfined
var foo = 2
// let
console.log(bar) // 报错
let bar = 2
- 暂时性死区
在代码块内,使用let命令声明变量之前,该变量都是不可用的。这种语法称为‘暂时性死区(TDZ)’
if (true) {
// TDZ开始
tmp = 'abc'
console.log(tmp) // ReferenceError
let tmp; // TDZ结束
console.log(tmp) // underfined
tmp = 123
console.log(tmp) // 123
}
暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在,但是不可获取,只有等到声明变量的哪一行代码出现,才可以获取和使用该变量
- let 不允许在同一作用域重复声明变量
function func () {
let a = 10;
var a = 1;
} // 报错
function func () {
let a = 10;
let a = 20;
} // 报错
同时,也不能在函数内部重新声明参数
function func (arg) {
let arg // 报错
}
function func(arg) {
{
let arg; // 报错
}
}
- 关于for循环
for 循环中存在块级作用域,在循环中,我们使用var声明一个变量,循环结束后,我们希望这个变量被销毁,但是var 声明的变量具有变量提升,所以我们在循环结束后,这个变量还是存在全局作用域中,会污染我们的全局作用域。这个时候我们可以使用let 来声明循环中变量,就可以解决这个问题。
// 使用var
for (var i = 0; i < 10; i++) {
// ....
}
console.log(i) // 10
// 使用let
for (let i = 0; i < 10; i++) {
// ....
}
console.log(i) // ReferenceErroe: i is not defined
注意:for 循环设置循环变量的那一部分是一个父作用域,而循环体内部是一个单独的子作用域。
for (let i = 0; i < 3; i++) {
let i = 'abc'
console.log(i)
}
// abc
// abc
// abc
2、const
- const 声明一个只读的常量。一旦声明,常量的值就不会改变。
const PI = =3.1415;
PI = 3; // TypeError: Assignment to constant variable
- const 一旦声明变量,就必须立即初始化,只声明不赋值,就会报错。
const foo; // // SyntaxError: Missing initializer in const declaration
- const的作用域与let命令相同:只在声明所在的块级作用域内有效。
if (true) {
const MAX = 5;
}
MAX // Uncaught ReferenceError: MAX is not defined
- const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
if (true) {
console.log(MAX); // ReferenceError
const MAX = 5;
}
- const声明的常量,也与let一样在同一作用域中不可重复声明。
var message = "Hello!";
let age = 25;
// 以下两行都会报错
const message = "Goodbye!";
const age = 30;
- const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。
const foo = {};
// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123
// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only
注意:上面代码中,常量foo储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。
最后
如果文章中有错误,请务必指出,万分感谢。