JS作用域
- 全局作用域
- 函数作用域
- 块级作用域(ES6)
块级作用域
避免内层变量覆盖外层变量
function f(){
let a=1;
if(true){
let a=10;
console.log(a,'内层') //10
}
console.log(a,'外层') //输出1,如果是var定义的,则会输出10
}
f();
简化立即执行函数
// IIFE
(function () {
var a = ...;
}());
// 块级作用域
{
let a =... ;
}
块级作用域必须有大括号。
函数可以在顶层作用域和块级作用域之中声明,在块级作用域内优先使用函数表达式。
let
let声明的变量仅在块级作用域生效
for(var i = 0; i<5; i++) {
setTimeout(function(){
console.log(i);
},1000);
} //输出5次5,i是全局变量
for(let i = 0; i<5; i++) {
setTimeout(function(){
console.log(i);
},1000);
} //输出01234,let在块级作用域内有效、形成闭包
let不存在变量提升、不能重复声明
console.log(a); //ReferenceError
let a=1;
console.log(a); //Identifier 'a' has already been declared
let a=1;
console.log(b); //undefined var有变量提升
var b=1;
暂时性死区TDZ
区块中存在let或者const,会形成封闭作用域。在声明之前使用会报错。直到声明后才能获取和使用变量。
if (true) {
a = 1;
console.log(a); //ReferenceError
let a;
}
const
声明一个只读常量,不可修改
const a=100;
a=1000;
//Uncaught TypeError: Assignment to constant variable.
与let一致,块级作用域内有效,且没有提升、不可以重复声明
if (true) {
const a = 1;
}
console.log(a); //Uncaught ReferenceError: a is not defined
注:
const 并非保存的值不可改变而是变量指向的内存地址保存的数据不可改变。
简单类型数据(null,undefined,boolean,number,string),变量就保存在变量指向的内存地址。
复杂类型数据(对象和函数),变量指向的内存地址保存的只是一个指向实际数据的指针。const保证不变的是指针,不能控制指向的数据结构。
对象冻结使用Object.freeze({}) ,严格模式下强行修改变量,会产生错误。
const person={
name:'lm'
}
person.name='ls';
console.log(person); //{name: "ls"}
总结
- var定义的变量,可以跨块访问, 不能跨函数访问。
- let定义的变量,只能在块作用域里访问,不能跨块、跨函数访问。
- const用来定义常量,使用时必须初始化(必须赋值),只能在块作用域里访问,而且不能修改(简单类型,引用类型除外)。
- let和const没有变量提升、不能重复声明、只能在块级作用域访问。
- let 和const声明的变量不会挂在window上,var 声明的会挂在 window上。
var a=123;
console.log(this.a); //123
let b=123;
console.log(this.b); //undefined
const c=123;
console.log(this.c); //undefined