let
对变量的声明
特性
- let 只在命令所在代码块有效
- 不存在变量提升
- 区块中存在let const 会形成封闭作用域(在定义此之前使用typeof 会抛出 //ReferenceError)
- 相同作用域不可重复声明(函数内部不可重新声明参数)
1.let 只在命令所在代码块有效
{
let a = 10
}
a //a is not defined
for循环计数适合使用let命令,仅作用域有效,普通var声明会全局有效
2. let 不存在变量提升
typeof a //"undefined"
typeof b //ReferenceError: b is not defined(报错)
let b = 1
3.区块中存在let const 会形成封闭作用域(在变量声明前使用会报错,即“暂时性死区”)
var o = 1
{
o = 2 //ReferenceError: o is not defined
let o
}
function bar(x=y, y=2){}
bar() //ReferenceError: y is not defined(x=y,此时y还没有声明,属于“死区”)
4.相同作用域不可重复声明(函数内部不可重新声明参数)
function(a) {
let a //报错
var b
let b //报错
{
let a //不报错
}
}
块级作用域
在es6之前存在两种作用域类型:
- 全局作用域
- 块级作用域
由var声明的变量都存在变量提升
es6使用let和const体现块级作用域,不存在变量提升,但在es6中var依旧存在变量提升
1.es5的问题
var tmp = new Data()
function f() {
console.log(tmp);
if (false) {
var tmp = "hello world"; //变量提升,内层tmp变量覆盖外层tmp变量
}
}
f(); // undefined
2.es6的块级作用域
- 外层作用域无法读取内层作用域的变量
- 内层作用域可以定义外层作用域的同名变量
- 块级作用域外部无法调用块级作用域内部定义的函数
针对函数
- es5中规定函数可在顶层作用域,函数作用域中声明,不可在块级作用域中声明,但声明了浏览器也支持
- es6可在块级作用域中声明,声明行为相当于let,外部不可访问,但浏览器有的不遵循~
'use strict';
if (true) {
function h() {return 0}
}
h() //Uncaught ReferenceError: h is not defined
es6的浏览器遵循如下规则
- 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
- 函数声明还会提升到所在的块级作用域的头部
所以
if (true) {
function h() {return 0}
}
h() //0 非严格模式下,不报错
但是
if (false) {
function f() { console.log('I am inside!'); }
}
f(); //f is not a function
因为相当于var变量提升后是这样的
var f = undefined;
if (false) {
function f() { console.log('I am inside!'); }
}
f(); //f is not a function
- let 实际为js新增了代码块级作用域,块级作用域中可声明函数(仅在大括号中有用)但在块级作用域之外不可使用 (要避免,必须时写成函数表达式)
- 严格模式下,函数只能在顶层作用域或者函数内声明,其他情况(比如if代码块,循环代码块)下声明会报错
const
特性
- const声明只读常量,修改会报错,只声明不赋值也会报错
- 不提升,同上存在暂时性死区,声明后才可用
- 不可重复声明常量
- 声明常量保存的是地址(即不能改变常量的指向,但可以改变其指向地址里的内容)
const foo = {}
foo.prop = 123
foo.prop //123
const foo = Object.freeze( { } ) 可将对象冻结, 不可添加新属性。
const foo = Object.freeze({})
foo.prop = 123 //添加新属性不起作用
但是上述方法,没有冻结对象里的所有属性,冻结对象里的所有属性:
var constantize = (obj) => {
Object.freeze(obj)
Object.keys(obj).forEach( (key, value) => {
if(typeof obj[key] === 'object') {
constantize(obj[key])
}
})
}
跨模块常量
export 输出
import 引用
全局对象属性
- 浏览器全局对象是 window对象 ,全局对象的属性 == 全局变量
a = 2
window.a //2
- var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。
- 不是全局对象的属性返回undefined
其他
- do 关于使得块级作用域可以变为表达式,可以返回值
- 引入global作为顶层对象