ES6(2015)新的声明方式 letconst
Posted 优小U
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ES6(2015)新的声明方式 letconst相关的知识,希望对你有一定的参考价值。
1. 作用域
常见的作用域主要分为几个类型:全局作用域、函数作用域、块状作用域、动态作用域。
对象 | 类型 |
---|---|
global/window | 全局作用域 |
function | 函数作用域(局部作用域) |
{} | 块状作用域 |
this | 动态作用域 |
全局作用域
变量在函数或者代码块 {}
外定义,即为全局作用域
。不过,在函数或者代码块{}
内未定义的变量也是拥有全局作用域的(不推荐)。
var course = "es"
// 此处可调用 course 变量
function myFunction() {
// 函数内可调用 course 变量
}
如果变量在函数内没有声明(没有使用 var 关键字),该变量依然为全局变量。
// 此处可调用 course 变量
function myFunction() {
course = "es"
// 此处可调用 course 变量
}
以上实例中 course 在函数内,但是拥有全局作用域,它将作为 global 或者 window 的属性存在。
函数作用域
在函数内部定义的变量,就是局部作用域。函数作用域内,对外是封闭的,从外层的作用域无法直接访问函数内部的作用域!
function bar() {
var testValue = 'inner'
}
console.log(testValue)
// 报错:ReferenceError: testValue is not defined
如果想读取函数内的变量,必须借助 return 或者闭包。
function bar(value) {
var testValue = 'inner'
return testValue + value
}
console.log(bar('fun')) // "innerfun"
闭包的方式:
function bar(value) {
var testValue = 'inner'
var rusult = testValue + value
function innser() {
return rusult
}
return innser()
}
console.log(bar('fun')) // "innerfun"
return 是函数对外交流的出口,而 return 可以返回的是函数,根据作用域的规则,函数内部的子函数是可以获取函数作用域内的变量的。
块状作用域
在ES6之前除了全局作用域就是函数作用域,一直没有自己的块状作用域。在 ES6 中已经改变了这个现象,块状作用域得到普及。关于什么是块,只要认识 {} 就可以了。
if (true) {
let a = 1
console.log(a)
}
在这个代码中, if
后{}
就是“块”,这个里面的变量就是拥有这个块状作用域,按照规则, {}
之外是无法访问这个变量的。
动态作用域
在 javascript 中很多同学对this
的指向时而清楚时而模糊,其实结合作用域会对this
有一个清晰的理解。不妨先来看下这段代码:
window.a = 3
function test() {
console.log(this.a)
}
test.bind({
a: 2
})() // 2
test() // 3
在这里bind
已经把作用域的范围进行了修改指向了 { a: 2 }
,而 this
指向的是当前作用域对象。
变量的作用域是在定义时决定而不是执行时决定,也就是说词法作用域取决于源码,通过静态分析就能确定,因此词法作用域也叫做静态作用域。 相反,只能在执行阶段才能决定变量的作用域,那就是动态作用域。
2. let
ES6 新增了let命令,用来声明变量。
1.let 声明的全局变量不是全局对象window的属性
var a = 5
console.log(window.a) // 5
let a = 5
console.log(window.a) // undefined
2.用let定义变量不允许重复声明
var a = 5
var a = 6
console.log(a) // 6
let a = 5
let a = 6
// VM131:1 Uncaught SyntaxError: Identifier 'a' has already been declared
// at <anonymous>:1:1
3.let声明的变量不存在变量提升
function foo() {
console.log(a)
var a = 5
}
foo() //undefined
上述代码中,a
的调用在声明之前,所以它的值是 undefined
,而不是 Uncaught ReferenceError
。实际上因为 var
会导致变量提升。而对于 let 而言,变量的调用是不能先于声明的:
function foo() {
console.log(a)
let a = 5
}
foo()
// Uncaught ReferenceError: Cannot access 'a' before initialization
4.let声明的变量具有暂时性死区
只要块级作用域内存在let
命令,它所声明的变量就绑定在了这个区域,不再受外部的影响。
var a = 5
if (true) {
a = 6
let a
}
// Uncaught ReferenceError: Cannot access 'a' before initialization
上面代码中,存在全局变量 a
,但是块级作用域内let
又声明了一个局部变量a
,导致后者绑定这个块级作用域,所以在let
声明变量前,对a
赋值会报错。
ES6 明确规定,如果区块中存在 let
和 const
命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
总之,在代码块内,使用 let
命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”。
5.let 声明的变量拥有块级作用域
let
实际上为 JavaScript 新增了块级作用域
{
let a = 5
}
console.log(a) // undefined
a
变量是在代码块 {}
中使用let
定义的,它的作用域是这个代码块内部,外部无法访问。
3. const
不能被改变的叫做常量,ES5中定义一个常量:
Object.defineProperty(window, 'PI', {
value: 3.14,
writable: false
})
console.log(PI)
PI = 5
console.log(PI)
const
除了具有let
的块级作用域和不会变量提升外,还有就是它定义的是常量
,在用 const
定义变量后,我们就不能修改
它了,对变量的修改会抛出异常
。
const PI = 3.1415
console.log(PI)
PI = 5
console.log(PI)
// Uncaught TypeError: Assignment to constant variable.
这个代码块中因为对 PI 尝试修改,导致浏览器报错,这就说明 const
定义的变量是不能被修改的,它是只读的。
注意:const 声明的变量必须进行初始化,不然会抛出异常 Uncaught SyntaxError: Missing initializer in const declaration。
需要注意的是,const
实际上保证的并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。
const obj = {
name: 'xiaoming',
age: 18
}
obj.school = 'qinghua'
console.log(obj)
// {name: "xiaoming", age: 18, school: "qinghua"}
虽然定义的对象是const
,但是只是保证地址值不变,地址指向的内存空间的值是可以变的。
如何让对象或者数组这种引用数据类型也不被改变呢?
Object.freeze(obj)
// 只是浅层冻结,只会对最近一层的对象进行冻结,并不会对深层对象冻结。
以上是关于ES6(2015)新的声明方式 letconst的主要内容,如果未能解决你的问题,请参考以下文章