letconst及块级作⽤域
本系列是在平时阅读、学习、实际项⽬中有关于es6中的新特性、⽤发的简单总结,⽬的是记录以备⽇后温习;本系列预计包含let/const、箭头函数、解构、常⽤新增⽅法、Symbol、Set&Map、Proxy、reflect、Class、Module、Iterator、Promise、Generator、async/await
let/const为我们带来了什么?
let
1. 约束变量提升
(function foo() {
console.log(a);
let a = 1;
})();
// Uncaught ReferenceError: a is not defined
总结下来就是⼀句:在变量使⽤之前,必须先要声明,变量声明永远在使⽤之前。
2. 带来了块级作⽤域
// es5
(function(){
if(false) {
var temp = 1;
}
console.log(temp); // undefined
})();
</span><span >//</span><span > es6</span>
(<span >function</span><span >(){
</span><span >if</span>(<span >false</span><span >) {
let temp </span>= 1<span >;
}
console.log(temp); </span><span >//</span><span > Uncaught ReferenceError: temp is not defined</span>
})();</pre>
从代码中我们可以很清晰看到es6的let的块级作⽤域,那么块级作⽤域有什么应⽤呢?举个例⼦:
var fnArr = [];
for(var i = 0; i < 5; i++) {
fnArr.push(function() {
console.log(i);
});
}
fnArr[0](); // 5
fnArr[1](); // 5
fnArr[2](); // 5
fnArr[3](); // 5
fnArr[4](); // 5
console.log(i); // 5
如果没有仔细分析,执⾏的结果是不是有些出乎意料呢?是的,我们本意在for循环内部使⽤的变量i被泄露成了全局变量,⽽且在for循环的每⼀次循环,变量i并没有被重新声明,实际上数组fnArr中保存的每⼀个函数中引⽤的都是同⼀个变量i,所以才导致了现在的结果,那怎么让代码按照我们最初的想法运⾏呢?来看es5中常⽤的解法
for(var i = 0; i < 5; i++) {
(function(j) {
fnArr1.push(function() {
console.log(j);
});
})(i)
}
fnArr1[0](); // 0
fnArr1[1](); // 1
const的作用
fnArr1[2](); // 2
fnArr1[3](); // 3
fnArr1[4](); // 4
console.log(i); // 5
看起来是解决了,这⾥实际上⽤到了闭包的⽅法,fnArr1中每⼀项函数引⽤的j都是当前循环时i的⼀个副本,这样就解决了前⾯的问题,但是还有⼀个问题:变量i仍然隐式得泄露到了全局
var fnArr1 = [];
for(let i = 0; i < 5; i++) {
fnArr1.push(function() {
console.log(i);
});
}
fnArr1[0](); // 0
fnArr1[1](); // 1
fnArr1[2](); // 2
fnArr1[3](); // 3
fnArr1[4](); // 4
console.log(i); // Uncaught ReferenceError: i is not defined
OK,问题解决了,仅仅是将’var‘替换成了let,这就是let带来的便利。
3. 产⽣暂时性死区&禁⽌重复声明
// 什么是禁⽌重复声明呢?先不给书⾯解释,来看⼀个es5中经常的写法
(function() {
var temp = 1;
var temp = 2;
var temp = function() {
return 1;
};
})();
上⾯这段代码执⾏没有任何问题,最终temp被赋值为⼀个函数
(function() {
let temp = 1;
var temp = 2; // Uncaught SyntaxError: Identifier 'temp' has already been declared
var temp = function() {
return 1;
};
})();
在第三⾏时就抛出了⼀个错误:temp已经被声明,是的,let声明过的变量,是不允许再次被声明的,再给⼏个例⼦巩固⼀下:
看出来了吗?只要是在let声明所在的作⽤域,就不允许再次声明同名变量(包括函数声明)
var foo = 1;
if(true) {
foo = 2; // Uncaught ReferenceError: foo is not defined
let foo;
}
看到let的’霸道‘了吧?只要在let所在的作⽤域,同名的变量就会被let占有,不允许重复声明,同时也要遵守let的规则4. 全局变量不再作为window对象的属性
var foo = 1;
(function() {
bar = 2;
})();
window.foo; // 1
window.bar; // 2
是的,es5中,全局变量(包括意外泄露的)都将⾃动被添加为window对象的属性
let foo = 1;
window.foo; // undefined
⼀切尽在不⾔中。。。
const
1. let所拥有的特性,const都有,同时const还有⼀条:const声明的变量必须进⾏初始化,并且不能再被重新赋值
const temp = 1;
temp = 2; // Uncaught TypeError: Assignment to constant variable.
注意是不能被重新赋值,这样是⽐较准确的,其实const声明的变量是可以被修改的,当const声明的变量被初始化为复杂数据类型时,const声明的变量就是可变的,⾄于为什么,⾃⼰理解喽(变量标识符中保存的只是复杂数据类型内存地址⽽已。。。)
const temp = {};
temp.foo = 'aa'; // 这⾥没问题
temp = {foo: 'aa'}; // 这⾥就会抛出异常
for循环中的变量声明
前⾯在记录let块级作⽤域的时候,我们使⽤了⼀个for循环的例⼦,这⾥我们不妨试着解析⼀下for循环的执⾏过程
var fnArr = [];
for(var i = 0; i < 3; i++) {
fnArr.push(function() {
console.log(i);
});
}
</span><span >//</span><span > 伪代码</span>
<span >var</span><span > fnArr;
fnArr </span>=<span > [];
{
</span><span >var</span><span > i;
i </span>= 0<span >;
</span><span >if</span>(i < 3<span >) {
fnArr.push(</span><span >function</span><span >() {
console.log(i);
})
}
i</span>++<span >;
</span><span >if</span>(i < 3<span >) {
fnArr.push(</span><span >function</span><span >() {
console.log(i);
});
}
i</span>++<span >;
...
}</span></pre>
这⾥可惜清晰得看到所有的i都是⼀个i。。。那使⽤了let以后呢?
var fnArr = [];
for(let i = 0; i < 3; i++) {
fnArr.push(function() {
console.log(i);
});
}
</span><span >//</span><span > 伪代码</span>
<span >var</span><span > fnArr;
fnArr </span>=<span > [];
{
let i;
i </span>= 0<span >;
</span><span >if</span>(i < 3<span >) {
let i </span>=<span > i;
fnArr.push(</span><span >function</span><span >() {
console.log(i);
})
}
i</span>++<span >;
</span><span >if</span>(i < 3<span >) {
let i </span>=<span > i;
fnArr.push(</span><span >function</span><span >() {
console.log(i);
});
}
i</span>++<span >;
...
}</span></pre>
是不是看出点名堂?其实我们完全可以这样理解,在每⼀次循环中都重新声明了i,并且被赋值为外层i的当前值。(注意啊,这⾥只是伪代码,便于理解,实际中let i = i是会抛出异常的)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。