变量提升机制(2)
目录
LET创建的变量不允许重复定义
在一个作用域,重复声明报错 Identifier 'a' has already been declared
LET创建的变量不存在变量提升
在ES6中基于LET/CONST等方式创建变量或者函数,不存在变量提升机制
也会切断全局变量和WINDOW属性的映射机制
虽然没有变量提升机制,但是在当前作用域代码自上而下执行之前,浏览器会做一个重复性检测(语法检测)(浏览器已经记住当前作用域下有哪些变量)
在私有作用域时,
若当前作用域有声明a,在声明前使用依旧报错(Cannot access 'a' before initialization),因为浏览器也已经记住当前作用域下的变量名,若没有声明,会沿作用域链查找,使用上级作用域的。
在私有作用域中,只有以下两种情况是私有变量
A:声明过的变量(带VAR/FUNCTION)
B:形参也是私有变量
* 剩下的都不是自己私有的变量,都需要基于作用域链的机制向上查找
当私有作用域的私有变量,操作的是自己,和全局作用域的变量没有关系;
不是私有变量,和上级作用域有关系,赋值则修改的是上级的变量。
所以说私有作用域一定要注意变量是否声明!!!
console.log(a, b);//Cannot access 'a' before initialization
let a = 10,
b = 10;
let fn = function () {
// console.log(a,b);//Cannot access 'a' before initialization
// console.log(b); //10
let a = b = 20;
// let a=20;
// b=20; 全局作用域的b
console.log(a, b);//20 20
};
fn();
console.log(a, b); //10 20
暂时性死区
当前作用域,声明前调用变量,都会报错Cannot access 'a' before initialization,这就涉及到一个概念——暂时性死区。
“暂时性死区”也意味着typeof
不再是一个百分之百安全的操作。
console.log(a);//=>Uncaught ReferenceError: a is not defined
console.log(typeof a);//=>"undefined" 在原有浏览器渲染机制下,基于typeof等逻辑运算符
检测一个未被声明过的变量,不会报错,返回UNDEFINED
console.log(a);//=>Uncaught ReferenceError: a is not defined
console.log(typeof a);//=>Uncaught ReferenceError: a is not defined
let a;//let声明后,在没有声明这个变量的时候,使用TYPEOF检测会直接报错
ES6规定暂时性死区和
let
、const
语句不出现变量提升,主要是为了减少运行时错误,防止在变量声明前就使用这个变量,从而导致意料之外的行为。这样的错误在ES5是很常见的,现在有了这种规定,避免此类错误就很容易了。
概念扫盲
上级作用域
当前函数执行,形成一个私有作用域A,A的上级作用域是谁,和他在哪创建(定义)的有关系,在哪个作用域创建的,它的上级作用域就是谁
堆内存和栈内存
JS中的内存分为堆内存和栈内存
* 堆内存:存储引用数据类型值(对象:键值对 函数:代码字符串)
* 栈内存:提供JS代码执行的环境和存储基本类型值
[堆内存释放]
* 让所有引用堆内存空间地址的变量赋值为null即可(没有变量占用这个堆内存了,浏览器会在空闲的时候把它释放掉)
[栈内存释放]
一般情况下,当函数执行完成,所形成的私有作用域(栈内存)都会自动释放掉(在栈内存中存储的值也都会释放掉),但是也有特殊不销毁的情况:
1.函数执行完成,当前形成的栈内存中,某些内容被栈内存以外的变量占用了,此时栈内存不能释放
2.全局栈内存只有在页面关闭的时候才会被释放掉
如果当前栈内存没有被释放,那么之前在栈内存中存储的基本值也不会被释放,能够一直保存下来
i++和++i
i++:自身累加1 (先拿原有值进行运算,运算结束后,本身累加1)
++i:自身累加1 (先自身累加1,拿累加后的结果进行运算)
var k = 1;
console.log(5 + (k++), k);//=>6 2
k = 1;
console.log(5 + (++k), k);//=>7 2