let创建了块级作用域,每次循环时内部的块级作用域都会去访问外层块级作用域中的变量i,而外层块级作用域中的变量i都不同,所以打印0-9;类似于闭包:内部函数返回到外部,保持其作用域链不释放。
var arr = [];
for(let i = 0; i < 10; i++){arr[i] = function(){console.log(i);}
}
for(var j = 0; j < 10; j++){arr[j]();
}
函数声明提升只在当前块级作用域内,不像var声明提升是作用域中逐级提升的。
但是不推荐在块级作用域中声明函数——>使用函数表达式。
{let a = 1;{// 函数声明提升只会在当前块级作用域内a(); // 10function a(){console.log(10);}}console.log(a); // 1
}
结论先行:const同样可以创建(产生)块级作用域。
const声明了一个引用类型的值,只能保证栈中的引用值的地址不改变,而堆中的引用值本身是可以被修改的。
------>解决方案:Object.freeze()
方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性。
const obj = {name: 'white'
}
// 对象冻结后,无法修改/增加对象的属性值
Object.freeze(obj);
obj.name = 'he';
obj.age = 22;
console.log(obj); // {name: 'white'}
------>但是如果引用值的属性仍然为引用值,仍可以改变引用值内部引用值的值
// 若对象的属性值为一个引用类型的值呢?
const obj1 = {friends: {name: 'white',fav: 'basketball'}
}
Object.freeze(obj1);
obj1.friends.name = 'jake';
console.log(obj1);
------->解决方案:循环冻结
const obj1 = {friends: {name: 'white',fav: 'basketball'}
}
myFreeze(obj1);
obj1.friends.name = 'jake';
console.log(obj1);function myFreeze(obj){Object.freeze(obj);// 遍历对象属性for(var key in obj){if(typeof(obj[key]) === 'object' && obj[key] != null){myFreeze(obj[key]);}}
}
但很少用,源头上解决这个问题:
const http = require('http');
定义模块时,最后一步return实例化对象,不会(不允许)对父级构造器进行修改。
浏览器环境中顶层对象是window。
var function定义的全局变量的值与顶层对象window的同名属性值相同。
var a = 2;
//当我修改变量时,名字写错了,但 window 的属性值仍能访问到,不合理
b = 1;
console.log(window.b); // 1
而let、const定义的全局变量与在顶层对象window上找不动同名属性。
注:不同环境中顶层对象不同;
浏览器:window;
node:global。