** 声明 **:本文只是在本人学习时得到的一些知识,如果发现问题可以与我联系,内容有不实之处请见谅。
一、前言
在ES3的版本(就是那种1000个人写出999种版本的....哈哈哈),第一次见到js的时候我很激动,握草什么!怎么能有这么灵活的语法~~~java简直是个渣渣老是和裹脚布一样辣么长,但是.....凡事有利就有弊,比如说下面这段代码
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 这个等于6哦
机智的你肯定发现问题了吧!其实等于的是10,啧啧!为什么嘞~(大神们绕道->_->)

因为这个
i被莫名提拔成为了全局变量,所以i的值一直在被覆盖产生了泄露在ES3中只有var类型的时候非常的方便,不要管什么变量直接扔就行

但是!!!但是!!!重点来了,js中使用var会出现变量等级提升的特性,用例子来说就是
console.log(a); // 输出 undefined
var a = 1;
明白了不?啊~~不明白?就是说js在使用var时不管它出现在那个位置都会放到最前面进行声明就像是关系户总会比我们快一点,上面的例子可以这么看
var a; // 嘿嘿,人家可是var,有特权
console.log(a); // 输出 undefined
a = 1;
ok!我们都很痛恨这种不按规矩办事的人,所以清官~哦,不!是let变量出来了
二、let
let这位清官非常守自己的本分除了在本身块级作用域里面能找得到它,在外面更本找不到!嗯....确实和清官挺像的,来个代码吧
{
console.log(a); // 报错 ReferenceError |T_T我是清官没特权
let a = 10;
var b = 1;
}
a // ReferenceError: a is not defined. |T_T外面果然都不知道我
b // 1
既然是清官眼里也是揉不得沙子
var a = 123;
function guanxihu(a){ // ReferenceError | var a:我擦我被拒绝入境了
a = 'abc'; // ReferenceError
let a;
}
这其实是TDZ(暂时性死区)也就是说在let这个清官会把外界的恶势力挡住,并且自己也不会插队。也就是说在块级作用域中当存在let变量声明的时候,前面不允许出现相应变量
{
// TDZ 开始
a = 'abc'; // ReferenceError
console.log(a); // ReferenceError
let a; // TDZ 结束
console.log(a); // undefined
a = 123;
console.log(a); // 123
}
总结就是进入当前作用域时相应变量已经存在但是不可获取,只有当出现相应的变量声明后才会解除锁定
那你说我让清官干完活再换关系户就好了,比如这样
{
let a = 1;
...........(不可描述的事情)
var a = 2;
}
不好意思这会产生错误
Identifier 'tmp' has already been declared
也就是这个位置已经占了~~(毕竟上级觉得这个人做的很不错啊,换了人我的业绩过不去了怎么办)
相对的上级也怕出现两个清官就会闹出很多事,所以下面这样也是不行
{
let a = 1;
let a = 2; // ReferenceError
}
好处
啧啧还记得第一次看到匿名自执行函数(IIFE)的时候觉得这个牛逼啊,也不会污染变量想出这个的肯定是神人
(function () {
var a = ...;
...
}());
但是这个终归是技巧,当我们有了let之后
{
let a = ...;
...
}
干净!简单!符合人的思维!T*D怎么才出来这个(更多的妙用可以自行体会,核心的原理都是上面说的那些)
注意
由于ES5规定函数不能在块级作用域申明(浏览器不报错会将函数设置成var在块级函数的表现),但是ES6又引入了,不过这让浏览器小弟们非常为难。比如
function f() { console.log('1'); }
(function () {
if (false) {
// 重复声明一次函数 f
function f() { console.log('2'); }
}
f();
}());
在ES5中是这样的
function f() { console.log('1'); }
(function () {
function f() { console.log('2'); }
if (false) {}
f(); // 2
}());
在ES6中是这样的
function f() { console.log('1'); }
(function () {
f(); // 1
}());
所以在块级作用域当中申明函数使用如下函数表达式而非声明式
let a = 'secret';
let f = function () {
return a;
};
注:ES6中声明块级作用域函数相当于声明了
let,不过具体需要看浏览器的解析
三、const
const像是一个占有欲非常强烈的人,它一旦被声明同时必须赋值,而且以后不能改变
const PI = 3.1415;
PI // 3.1415
PI = 3; // TypeError: Assignment to constant variable.
const HU;// SyntaxError: Missing initializer in const declaration
但是他还是有底线的哦~只占有自己的东西这与let一样都是在块级作用域中有效并且也是存在TDZ,深入的讲就是每个const声明的变量都指向一个地址,这个地址是不能被改变的,但是里面存储的东西是可以进行替换的
const a= {};
a.prop = 123;
console.log(a.prop) // 123
a= {}; // TypeError: "foo" is read-only
四、历史遗留的全局属性
在发展中留下了许多暗伤比如一直引发很多问题的
window.a = 1;
a // 1
a = 2;
window.a // 2
全局对象的属性赋值与全局变量的赋值,是同一件事,这会引发很多原本不应该存在的问题,所以这种块级作用域的变量出现了!
var a = 1;
window.a // 1
let b = 1;
window.b // undefined
五、结语
哈哈哈~~平常话讲的少只能在这种时候扯一点,内容有误的地方还请大家指出,有很多废话也请大家见谅,晚安!