块级作用域
- 通俗的讲,就是一对花括号中的区域
- 块级作用域可以嵌套
let声明变量
特点1:只作用在当前块级作用域内
{
let a = 1;
{
console.log(a); // 1
let b = 2;
}
console.log(b); // 报错:b is not defined
// 注意是报错,而不是undefined
}
特点2:不能重新声明
var回顾1:
var dad = "我是爸爸";
console.log(dad); // 我是爸爸
var dad;
console.log(dad); // 我是爸爸
// 不会报错,因为变量提升,其实相当于
var dad;
dad = "我是爸爸"
console.log(dad); // 我是爸爸
console.log(dad); // 我是爸爸
var回顾2:
var dad = "我是爸爸";
console.log(dad); // 我是爸爸
var dad = "我才是爸爸";
console.log(dad); // 我才是爸爸
// 不会报错,因为变量提升,其实相当于
var dad;
dad = "我是爸爸"
console.log(dad); // 我是爸爸
dad = "我才是爸爸";
console.log(dad); // 我才是爸爸
let说明:
let son = "我是儿子";
let son = "我才是儿子";
// 报错:Identifier 'son' has already been declared
特点3:let不存在"变量提升"
var回顾:
console.log(dad); // undefined
var dad = '我是爸爸';
// 因为变量提升,其实相当于
var dad;
console.log(dad); // undefined
dad = '我是爸爸';
let说明:
console.log(dad); // 报错:dad is not defined
let dad = '我是爸爸';
特点4:暂存死区
var回顾:
var monkey = "我是美猴王";
{
console.log(monkey); // 我是美猴王
var monkey = "我觉得我还能再抢救一下";
}
console.log(monkey); // 我觉得我还能再抢救一下
// 因为变量提升,其实相当于
var monkey;
monkey = "我是美猴王";
//{
console.log(monkey); // 我是美猴王
monkey = "我觉得我还能再抢救一下";
//}
console.log(monkey); // 我觉得我还能再抢救一下
let说明:
let monkey = "我是美猴王";
{
// let声明的变量会在{}中形成一个封闭的作用域,即使向上的作用域中存在同名的变量,也是拿不到的
// 这就是暂存死区
console.log(monkey); // 报错:ReferenceError: monkey is not defined
let monkey = "我觉得我还能再抢救一下";
}
console.log(monkey);
const声明常量
- 特点1:const 声明常量的时候必须赋值,否则会报错
const a = 1; // 正确
const b; // 报错:Missing initializer in const declaration
- 特点2:const 声明常量不能被修改
- 特点3:只在当前块级作用域内有效(与let一样)
- 特点4:不能重复声明(与let一样)
- 特点5:不存在提升(与let一样)
- 特点6:常量为引用类型的时候,可以修改该常量
// const 只能保证声明常量所指向的地址不变,不能保证地址上的值不变
const xiaoming = {
age:14,
name:'小明'
}
console.log(xiaoming); // {age: 14, name: "小明"}
xiaoming.age = 20;
console.log(xiaoming); // {age: 20, name: "小明"}
xiaoming = {}; // 报错:Assignment to constant variable.
思考1:怎么防止常量为引用类型时能被修改的情况?
// 使用Object.freeze方法
const xiaoming = {
age:14,
name:'小明'
}
Object.freeze(xiaoming);
console.log(xiaoming); // {age: 14, name: "小明"}
xiaoming.age = 20;
console.log(xiaoming); // {age: 14, name: "小明"}
思考2:ES6之前怎么声明常量?
// 第一步:Object.defineProperty
// Object.defineProperty(参数1,参数2,参数3)用于定义一个对象的属性
// 参数1:目标对象
// 参数2:属性名称
// 参数3:配置属性(值,是否可修改等)
var CST = {};
Object.defineProperty(CST, "BASE_NAME", {
value: "小明",
writable: false
});
// 缺陷:虽然BASE_NAME属性无法修改,但还是可以给CST对象增加其他属性。
// 第二步:Object.seal
// 用途:禁止对象新增属性,所以可以解决第一步中的缺陷
Object.seal(CST);
// 封装一个定义常量的方法
// 1. 遍历属性和方法
// 2. 修改遍历到的属性的描述
// 3. Object.seal()
Object.defineProperty(Object, "freezePolyfill", {
value: function(obj) {
var i;
for (i in obj) {
if (obj.hasOwnProperty(i)) {
Object.defineProperty(obj, i, {
writable: false
});
}
}
Object.seal(obj);
}
});
const xiaoming = {
age: 14,
name: "小明",
};
Object.freezePolyfill(xiaoming); // xiaoming这个对象无法修改和新增属性了
Object.freeze 相当于 Object.defineProperty + Object.seal的效果
网友评论