1.let和const命令
·let命令(局部变量)
①用法类似于var(全局变量),但只在let命令所在的代码块内有效
②适用于for循环计数器
③不存在变量提升:var命令会发生“变量提升的现象”,即可以在声明之前使用,值为undefined,let一定要在变量声明后使用,否则报错。
console.log(foo); // undefined
var foo = 2;
console.log(bar); // referenceError
let bar = 2;
④暂时性死区:只要块级作用域内存在let命令,它所声明的变量就“绑定”这个区域,不再受外部影响。
var tmp = 123;
if(true){
tmp = 'abc'; // ReferenceError
let tmp;
}
在某一代码块内,使用let命令声明变量之前,该变量都是不可用的。 “暂时性死区”也意味着typeof不再是百分之百安全的操作。
⑤不允许重复声明:let不允许在相同作用域内,重复声明一个变量。也不允许在函数内部重新声明参数。
·块级作用域
没有块级作用域之前,只有全局作用域和函数作用域。let为javascript新增了块级作用域
function f1(){
let n=5;
if(true){
let n=10;
}
console.log(n); // 5 外层代码块不受内层代码块的影响
}
如果两次都用的var命令定义,则输出10.
{{{{
{let aa = "hello,world"} // 第五层块级作用域
console.log(aa); // 报错 // 第四层块级作用域
}}}} // 第四层作用域无法读取第五层变量
内层作用域可以定义外层作用域的同名变量
{{{{
let insane = 'Hello World';
{let insane = 'Hello World'}
}}}};
块级作用域的出现,实际上使得获得广泛应用的匿名立即执行函数表达式(匿名 IIFE)不再必要了。
// 普通函数
function fn(){
console.log("hello,我是普通函数");
}
// 调用
fn();
// 匿名函数 在函数后面加个括号即可执行该函数
(function(){
console.log("hello,我是匿名函数")
})();
// 块级作用域写法
{
console.log("hello,我是块级作用域函数");
}
块级作用域内部优先使用函数表达式
{
let a = 'secret';
let f = function(){
return a;
};
}
块级作用域必须要有大括号,如果没有大括号,JavaScript引擎就认为不存在块级作用域。
严格模式下,函数只能声明在当前作用域的顶层。
·const命令
①是一个只读常量,一旦声明,必须马上初始化。只声明不赋值会报错。
②作用域与let相同:只在声明所在的块级作用域内有效
③常量不提升,同样存在暂时性死区
④不可变的是地址,这个地址指向一个数据类型,可以为其增加新属性,但不能直接赋值
const foo = {};
foo.prop = 123;
console.log(foo.prop) // 123
foo = {} // 报错
const a = [];
a.push('hello'); // 可执行
a.length = 0; // 可执行
a = ['asd'] // 报错 typeError
⑤ 可以使用Object.freeze方法将对象冻结
ES6声明变量的六种方法: ①var ②function ③let ④const ⑤import ⑥class
·顶层对象
①在浏览器环境指的是window对象(指的是浏览器的窗口对象),在node指的是global对象
②在ES5中,顶层对象的属性和全局变量是等价的。在ES6中,var和function声明的全局变量依旧是顶层对象的属性,let、const、class命令声明的全局变量不属于顶层对象的属性。
var a = 1;
console.log(window.a) // 1
let b = 1;
console.log(window.b) // undefined
·globalThis
在任何环境下(浏览器、Web Worker、Node),globalThis都是存在的,都可以从它那拿到顶层对象,指向全局环境下的this
2.变量的解构赋值
·数组的解构赋值
ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值
“模式匹配”(只要等号两边模式相同,左边的变量就会被赋予对应的值)