目录
es5:
全局作用域 --> script 独立JS文件
函数作用域 -->
es6:
块作用域
无论在什么作用域下,只要没有声明就使用赋值得变量 (a=1;),会成为类似全局作用域得变量的存在
没有声明就赋值的变量会泄露,成为顶层/全局window对象的属性,在任何作用域都能访问到
var声明的全局变量会污染顶层对象的属性环境,即成为window的属性
全局环境和局部环境,全局作用域和局部作用域
全局环境是不会被卸载掉的,除非把浏览器关闭,或者把标签关了(人为回收了)
栗子:
<script>
window.onload = function () {
function show() {
var name = 'liang';
function hd() {
var age = '18';
}
hd();
}
show();
};
</script>
这里画个图示意:
不调用函数就不会开辟出内存空间,此时只是声明了函数,就像盖房,只是画了一个房子设计图,但还没动工,只是个计划,所以还没有开辟一块地开始建房。
延伸函数环境生命周期
每次调用函数都会开辟出新的一块内存空间,就像王者荣耀,每开一局都是新的一把游戏,跟上一把游戏没有关系。
栗子:
<script>
window.onload = function () {
function show() {
var n = 1;
function sum() {
console.log(++n);
}
sum();
}
show();
show();
show();
show();
};
</script>
控制台输出4个2,原因就是因为每次调用函数都是新的环境、新的内存空间、新的数据
解决的唯一方法:就是把show()环境的数据保留
因为每次调用函数都与上一次调用没有关系,上一次调用函数后的数据,以后都再也不会用到,不用就会被清除掉(原理可参考JS高级程序涉及第4版第94页)
那么如果调用后的函数数据一直有被用到,那么就会保留。不只是被用到的数据会被保留,整个环境中的数据都会被保留
<script>
window.onload = function () {
function show() {
var n = 1;
return function sum() {
console.log(++n);
}
sum();
}
let a = show();
a();
a();
a();
};
</script>
return 里返回的其实是匿名函数,但为了方便理解,这里还是设置了函数名。
这里不可以返回n, 因返回n只是把值返回到外部
运行结果:
若复制给一个新的变量b ,函数show()再一次被调用,那么数据就又是新的一批数据
let a = show();
a();
a();
a();
let b = show();
b();
b();
运行结果:
可以这样理解:
每赋值给一个新的变量,相当于调用一次show函数,就会开辟出新的一个内存环境,每个环境都是无关的,独立的,重新加载的数据
每调用一次被赋值的变量函数,相当于在当前环境,即当前数据基础上执行
接下来讨论另一种情况,栗子:
<script>
window.onload = function () {
function show() {
var n = 1;
return function sum() {
let m = 1;
function lee() {
console.log(++m);
}
lee();
}
}
let a = show();
a();
a();
};
</script>
那么此时会进行累加操作吗??
答案是不会。 。原因是因为当lee函数执行完之后,lee()里的数据就被清除掉了,数据没有被保留。sum()函数还是会被反复创建,跟前面是一个道理
解决:
return function lee() {
console.log(++m);
};
};
}
let a = show()();
a();
a();
运行结果:。n也可累加输出
那么构造函数如何实现以上内容呢?
<script>
window.onload = function () {
function Lee() {
let n = 1;
function sum() {
console.log(++n);
}
return {
sum: sum
};
}
let a = new Lee();
a.sum();
a.sum();
};
</script>
运行结果: 每new一个对象,都调用一次Lee构造函数,原理跟上面相同
块作用域
栗子:
<script>
{
let a = 1;
}
{
let a = 2;
}
</script>
画个图:
两个块,虽然名字相同,但是不同的数据,把不同的环境,不同的作用域存在的。所以可设置相同名。
在同环境,作用域中是不可以设置相同名的变量或函数的
a在外部不可以使用,会显示a is not defined错误
用var会把a放在全局作用域中,因为var没有块级作用域,但有函数作用域。
因为var历史比较早,块级作用域是在var后面推出的,为了考虑兼容性,就没把var纳入到块级作用域中,而推出了let和const
用法:需要开辟一个新的作用域,而这块作用域不需要重复调用,只需要执行一次,就用块作用域,但块作用域只能用let,不能用var。不污染全局环境