摘要:块状作用域提起中的关键字,第一个想法就是块状作用域。而如果通过这些关键词声明的,那么也就会声明到所在的作用域中。终于回到可以将变量绑定到所在的任意作用域中,通常是内部。避免不必要的出现。
读<你不知道的javascript>,想到哪里写到哪里。。。
块状作用域提起ES6中的let关键字,第一个想法就是块状作用域。
说到作用域,以前提及的都是全局作用域和函数作用域。当进行作用域查找的时候,永远是一层一层往上查找,直到找到第一个匹配的标示符时停止。
全局作用域就是整个作用域的最上层,当进行作用域查找的时候,全局作用域永远是最上一层,如果在全局作用域中依然无法找到,那么就会抛出referenceError。
而说到函数作用域,曾经读过一本书上面说到一个词“隐藏”变量和函数定义,觉得很贴切。把东西隐藏在函数中,避免污染外部作用域的同时,可以有效地进行模块化管理。
回到块状作用域,除了let,另外一个with关键字也创造了一个块状作用域。
function foo(obj) {
var c = 6;
with(obj) {
a = b;
c = 5;
var d = 7;
let e = 8;
}
console.log(c); // 5
console.log(d); // 7
console.log(e); // referenceError
}
var obj = { a:1, b:2 };
foo(obj);
我们都知道其中的a和b的作用域查找(LHS, RHS)都是在obj中找到。而如果无法再obj中找到,那么就会向上作用域继续找,这里的c就会找到foo函数中的c。而如果通过var这些关键词声明的,那么也就会声明到with所在的作用域中。
对于with,就相当于在外面又包了一层作用域,里面包含提供对象中的所有属性。
终于回到let, let可以将变量绑定到所在的任意作用域中,通常是{}内部。没了。。。
提升和var声明变量和函数声明,let不会进行提升。看看下面的几个例子:
console.log(a); // referenceError let a = 1;
console.log(b); // undefined; var b = 1;
foo(); // 3
function foo(){ console.log("3") }
foo(); // type error
var foo = function(){ console.log("4") }
foo(); // referenceError
let foo = function(){ console.log("5") }
说到提升,提一句:“函数会首先被提升,然后才是变量”。像之前的书里的一个例子:
bar(); // 3
function bar(){ console.log(1) };
var bar = function(){ console.log(2) };
function bar(){ console.log(3) }
提升以后看起来就像:
function bar(){ console.log(1) };
function bar(){ console.log(3) };
bar(); // 3
bar = function(){ console.log(2) };
这里需要提一句,var bar这一段由于bar在之前已经被声明过了,所以这里var bar会被忽略,而不是把bar设为null。
说到提升,还有一种特殊的情况,虽然不建议这么写,但是肯定会有人会踩到雷:
var a = true;
if(a) {
function foo(){ console.log(1) }
} else {
function foo(){ console.log(2) }
}
foo();
原书中说这种情况,由于提升,所以会输出2,而不是我们想要的1。但是我在chrome和firefox中试了一下,会按照想要的输出1。而在IE11中,却输出的是2。
所以,很明显,chrome和firefox对这种情况作了优化,但是还是有浏览器的差别,所以尽量不要这么声明函数。避免不必要的bug出现。
垃圾收集当使用闭包的时候,会造成一部分的内存不会进行释放。这是闭包的好处,也是闭包的坏处。好处就是我们可以在外部使用这个变量,而坏处就是有些不需要的变量也不会被释放。
一个简单的闭包:
function Foo(){
var a = [....];
// .....和a做些互动
var b = 0;
return function(){
return b++;
}
}
这里在闭包中,我们其实只需要保存b的内存就好,而a是不需要的。按照理想情况,a在Foo结束后就可以垃圾回收了(GC)。然而引擎有可能会保存着这个东西(取决于具体实现--你不知道的javascript),这就造成了内存的浪费。
那么就可以使用let块状作用域的特性,进行处理:
function Foo(){
{
let a = [....];
// ....和a做些互动
}
var b = 0;
return function(){
return b++;
}
}
这里,由于a的作用域只在{}中,所以当{}结束后就会释放a的内存,而不是长久占有内存。
循环这里只写出一个很有意思的观点。
我们都知道在循环中用let可以解决某个老生常谈的问题。但是总是转变不过来,为什么会解决这个问题。
var a = [];
for(var i = 0; i < 10; i++) {
a[i] = function(){ console.log(i) };
}
a[3](); // 10
var a = [];
for(let i = 0; i < 10; i++) {
a[i] = function(){ console.log(i) };
}
a[3](); // 3
所以到底let做了什么神奇的事情,解决了这个问题?
书中说了一句话:
for循环头部的let不仅将i绑定到了for循环的块中,事实上它将其重新绑定到了循环的每一个迭代中,确保使用上一个循环迭代结束时的值重新进行赋值。
然后给了一个等价的例子,一目了然:
var a = [];
{
let j;
for(j=0; j<10;j++){
let i = j; // 每个迭代重新绑定
a[i] = function(){ console.log(i) };
}
}
a[3](); // 3
最后啰嗦一句,const这个关键词,也是块状作用域,也是不提升。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/82421.html
摘要:前面不短时间持续投入了时间在做应用架构方面的考量一个是冒险进行了一次应用架构的调整另一个是跟进了的进展当然实际上是同一个事情也许错过的比收获的还多一些不过能走到现在也算幸运了毕竟单页面应用还面临很多不成熟之处国庆长假过去不少现在的想法估计会 前面不短时间持续投入了时间在做 React 应用架构方面的考量一个是冒险进行了一次应用架构的调整, 另一个是跟进了 Redux 的进展当然, 实际...
摘要:背景如图所示冯诺依曼计算机体系结构由于最近做业务需求做到发瘟借此发散一下思维最近业务需求的痛点如下基础代码骨架已固定业务流程固定然而业务中产品的配置需要非常灵活并且有可能需要跨过某段业务流程直接执行下一段直接方案当然是能够决定条件分支的但架 showImg(https://segmentfault.com/img/bVbrHbo?w=1920&h=981); 背景 如图所示, 冯诺依曼...
阅读 2365·2021-09-22 15:54
阅读 2075·2021-09-04 16:40
阅读 1096·2019-08-30 15:56
阅读 2865·2019-08-30 15:44
阅读 2391·2019-08-30 13:52
阅读 1324·2019-08-29 16:35
阅读 3578·2019-08-29 16:31
阅读 2765·2019-08-29 13:48