let-const-块级作用域的学习
let-const基本使用
const age = 18 // 不能修改
// 修改会报错: TypeError: Assignment to constant variable.
// 1.const保存的是一个引用类型(内存地址),不能修改引用类型.
// 可以通过引用找到对应的对象,去修改对象内部的属性值.
const info = {
mes: 'hello world!'
}
// 这个是允许的
info.mes = 'hello Fhup!'
console.log(info)
// 2.let/const定义的变量名不可以重复定义
// var aaa = '123'
// var aaa = '456'
// console.log(aaa) // 456
let bbb = '123'
// SyntaxError: Identifier 'bbb' has already been declared
// let bbb = '456'
console.log(bbb);
let-const作用域提升
// var有作用域提升
// console.log(foo) // undefined
// var foo = '123' // 源代码解析时 GO { foo: undefined }
/**
* ReferenceError: Cannot access 'bar' before initialization, 不能在初始化之前访问 bar
* ECMA262新规范中解释,在执行上下文时bar已经被创建出来,但是不能提前被访问
* 所以let/const 不能称之为作用域提升
*/
console.log(bar)
let bar = '123'
let-const执行过程
// VO/AO/GO -> 早期的标准
var age = 18
console.log(window.age);
window.toy = '枪'
console.log(toy)
// 最新的ECMA规范: VE代替VO, VE 指向 variables_:VariableMap(HashMap->HashTable)
// 自己理解: VE(相当于VO) 指向 variables_(相当于GO), 新规范内部实现已经慢慢脱离window(已经不是同一个对象),但为了兼容而存在.最新规范已经将let/const的变量保存在variables_里面,在执行上下文时bar已经被创建出来,但是不能提前被访问 所以我认为: let/const没有进行作用域提升,但是会在解析阶段被创建出来.
ES5块级作用域
// 声明对象的字面量
var obj = {
// 键值对
name: 'Fhup'
}
// ES5中没有块级作用域, var声明的类型是无效的,可以访问
// 块代码(block code)
{
// 里面写表达式, 可声明变量...
var foo = '123'
}
console.log(foo) // 123
// ES5只有二个东西形成作用域: 1.全局作用域 2.函数作用域
ES6块级作用域
// ES6的代码有块级作用域
// let/const/function/class有作用域的,外部不能访问
{
let foo = 'foo'
function bar() {
console.log('bar');
}
class Person {}
}
// console.log(foo) // ReferenceError: foo is not defined
// 函数可以访问,因为浏览器为了兼容以前的代码.让function失去块级作用域,(不同浏览器不同实现)
// 只支持ES6的浏览器,它就会报错
// bar()
let p = new Person() // ReferenceError: Person is not defined
if-switch-for块级代码
{
// 块级作用域中的var外部可访问,let外部不可访问
}
// let声明的变量只属于if语句内部使用
// if语句的代码就是块级作用域
// if(true) {
// var bar = 'bar'
// let foo = 'foo'
// }
// console.log(bar) // bar
// console.log(foo) // ReferenceError: foo is not defined
// switch语句的代码也是块级作用域
// var color = 'red'
// switch(color){
// case 'red':
// var xxx = 'xxx'
// let yyy = 'yyy'
// break;
// default:
// console.log('这是无色!');
// break;
// }
// console.log(xxx) // xxx
// console.log(yyy) // ReferenceError: yyy is not defined
// for语句的代码也是有块级作用域
// for(var i = 0; i < 1; i++) {
// var aaa = 'aaa'
// let bbb = 'bbb'
// }
// console.log(i) // 1
// console.log(aaa) // aaa
// console.log(bbb) // ReferenceError: bbb is not defined
// let声明的变量只属于for循环的内部使用,外部不能访问
// for(let x = 0; x < 1; x++) {}
// console.log(x) // ReferenceError: x is not defined
块级作用域的应用场景
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<button>1</button>
<button>2</button>
<button>3</button>
<button>4</button>
<script>
var btns = document.querySelectorAll("button");
// for语句的代码有块级作用域
// btns[i] 找 i 时,var没有作用域,找到全局, i = 4
// 解决方案:
// 使用let,形成块级作用域.所以i每次绑定为 0,1,2,3
// 使用闭包()()
for (var i = 0; i < btns.length; i++) {
btns[i].addEventListener("click", () => {
console.log("按钮" + i);
});
}
console.log(i);
</script>
</body>
</html>
块级作用域的补充
const names = ['aaa', 'bbb', 'ccc']
// for(let i=0; i< names.length; i++) {
// console.log(names[i]);
// }
// 过程:
// 有++的操作,不可以使用const
// {
// let i = 0
// console.log(names[i]);
// }
// {
// // 拿到上次的i,进行++的结果赋值给i
// let i = 1
// console.log(names[i]);
// }
// {
// let i = 2
// console.log(names[i]);
// }
// for...of 遍历数组(对象),没有++的操作,可以使用const
for(const item of names) {
console.log(item);
}
// console.log(item) // 使用var时,item的值为ccc
{
const item = 'aaa'
console.log(item);
}
{
const item = 'bbb'
console.log(item);
}
{
const item = 'ccc'
console.log(item);
}
暂时性死区
/**
* 暂时性死区:
* 在一个代码块中,使用let/const声明的变量,在声明之前,变量都是不可以访问的.
*/
var obj = 'obj'
// {}的内部区域称之为: 暂时性死区
if(true) {
console.log(obj) // ReferenceError: Cannot access 'obj' before initialization
let obj = 'xxx'
}
// 在开发中,多使用 const