一、声明变量的五种方式
- 传统方式:var、function
- ES6: let、const、import
二、let VS const
-
let和const声明的都是变量,const声明的变量是不允许指针重新指向的(但是存储的值是可以改变的,例如:存储的值是引用数据类型,可以基于地址改变堆内存中的信息)
赋值本身就是指针关联或者指针指向的过程// let声明的变量可以修改 let n = 12 n = 13 console.log(n) // 13 // const声明的不可以直接修改 const m = 12 m = 13 console.log(m) // Uncaught TypeError: Assignment to constant variable. // const声明的变量基于地址改变堆内存中的信息 const obj = { name: 'zs' } obj.name = 'ls' console.log(obj) // {name:'ls'}
三、let VS var
- 带var/function的存在变量提升,而let/const不村子啊变量提升机制
在全局代码执行之前,首先会变量提升:把当前上下文中所有带var/function关键字的提前声明(带var的只声明不定义,带function的会提前声明+定义)
// 带var的会变量提升
console.log(n) // undefined
var n = 12
相当于
var n
console.log(n)
n = 12
console.log(n) // VM226:1 Uncaught ReferenceError: Cannot access 'n' before initialization 不允许再声明之前使用它
let n = 12
之前创建函数都是 function fn() {} 但是现在不建议这么写,举例
// 变量提升: fn = 0x0000(堆内存)
fn() // ok
function fn() {
console.log('ok')
}
在函数创建之前可以正常使用,正常情况下应该是创建完后才能使用,所以这么写不严谨
现在建议用函数表达式创建函数
fn() // Uncaught ReferenceError: Cannot access 'fn' before initialization
const fn = function() {
console.log('ok')
}
这么写保证了严谨性
函数的变量提升在“新版本浏览器”中得坑爹机制
变量提升阶段:<br>
1. 没有出现在大括号当中,在新老版本中是一样的,都是声明加定义
2. 出现在大括号当中:<br>
<span style="color:red">[老版本浏览器]:</span>不论条件是否成立,都要把fn声明+定义,而且fn
只是全局上下文中得变量<br>
<span style="color:red">[新版本浏览器]:</span>为了兼容ES3/ES6,规则处理的非常复杂
2.1. 全局变量提升:如果创建函数的代码出现在"非函数或者对象得大括号中(例如:判断题,循环体,代码块...)",只会进行声明,不进行赋值了 =》 function fn;
console.log(fn) // 老版本浏览器中输出函数本身。 新版本浏览器中 输出undefined
if(1==1){
function fn() {
console.log('ok')
}
}
2.2. 代码执行进入到大括号当中:如果大括号中有function此时function xxx(){},此时当前大括号会形成一个私有的上下文,私有上下文中的第一件事情也是变量提升,它会把函数进行声明+定义(私有变量)
console.log(fn) // 老版本浏览器中输出函数本身。 新版本浏览器中 输出undefined
if(1==1){
// 私有上下文变狼提升:fn = 0x000000
console.log(fn) // 函数
function fn() { // 代码执行大这的时候,会把私有赏析文中,之前对fn的操作,映射给全局一份
console.log('ok')
}
fn = 12
console.log(fn) // 12
}
console.log(fn) // 函数
所以,真实项目中尽量不要把函数写在非函数/对象的大括号中。并且创建函数的时候尽可能用函数表达式
-
第二个区别。相同的上下文中,let不允许重复声明(而且检测是否重复声明发生在“词法解析阶段” 词法解析->变量提升->代码执行,也就是词法解析阶段检测到重复声明,则直接报错,代码一行都不会执行。);且不论基于什么方式声明的变量,只要在当前上下文中有了,则不允许再基于let/const声明。
词法解析阶段检测到重复声明,则直接报错,代码一行都不会执行
3. 暂时性死区(浏览器遗留BUG):基于typeof 检测一个未被声明的变量,不会报错,结果是undefined
但是如果在let声明之前用就会报错,所以可以理解为使用let 能解决浏览器暂时性死区问题
4. 块级私有上下文(作用域):
1.除函数或者对象的大括号之外,如果括号中出现 let/const 则会产生块级私有上下文
2.当前块级上下文也只是对let/const/function他们声明的变量有作用。
可以这么理解:
不会形成块级私有上下文
会形成块级私有上下文