声明变量的五种方案:
var function 传统方案
let const import ES6的新方案
var VS const:
let 和const声明的都是变量,const 声明的变量是不允许指针重新指向,但是存储的值是可以改变的,比如存储的值是引用数据类型,可以基于地址改变堆内存中的信息。
等号= 赋值本身就是指针关联或者指针指向的过程
let n = 12, 先创建12存在栈里面,再创建n,然后n和12关联,n指向12
let n = 12;
n = 13;
console.log(n); // 13
const m = 12;
m = 13; // 这里就报错了,指针重新指向的时候Uncaught TypeError: Assignment to constant variable.
console.log(m);
const m = {
name: 'qiuhan'
};
m.name = 'erina';
console.log(m); // {name: "erina"}
平时在项目中用const 的情况也比较多,比如想声明一个变量,这个变量指针不能再重新指向别的值,只能关联初始创建的值。项目中一般创建函数的时候用const,fn只能和这个函数关联,不能指向别的函数。
const fn = function() {}
var VS let:
- 带var/function 存在变量提升,而let/const不存在变量提升机制
- 在相同的上下文中,let不允许重复声明(而且检查是否重复声明发生在“词法解析阶段”)
- 此法解析-> 变量提升 -> 代码执行
- 也就是词法解析阶段检测到重复声明,则直接报错,JS代码一行(句)都不会执行
- 且不论基于什么方式声明的变量,只要在当前上下文中有了,则不允许再基于let/const声明;
- 暂时性死区(浏览器遗留BUG):基于typeof检测一个未被声明的变量,不会报错,结果是undefined
- 块级私有上下文(作用域)
- 除函数或者对象的大括号之外,如果括号中出现 let/const/function 则会产生块级私有上下文
- 当前块级上下文也只是对let/const/function他们声明的变量有作用
// 在全局代码执行之前,首先会变量提升:把当前上下文中所有带var/function关键字的提前声明或者定义
//(带var只是提前声明,带function会提前的声明+定义)
// var n;
console.log(n); // undefined
var n = 12;
console.log(n); //VM42645:1 Uncaught ReferenceError: n is not defined
let n = 12;
// 此写法不建议写
// 变量提升: fn = 0x000000;
fn(); // 'ok'
function fn() {
console.log('ok')
}
// 建议函数表达式方式创建函数
fn(); // Uncaught ReferenceError: Cannot access 'fn' before initialization
const fn = function () {
console.log('ok');
};
fn(); // 'ok'
// 函数的变量提升在新版浏览器中很变态
// 变量提升: fn = 0x000000; 声明+ 定义
console.log(fn); // 函数本身: 只是打印变量fn,非执行fn() { console.log('ok')}
function fn() {
console.log('ok')
}
- 在相同的上下文中,let不允许重复声明(而且检查是否重复声明发生在“词法解析阶段”) ```javascript var n = 12; var n = 13; console.log(n); // 13
=============================================================================== // 注意ok都没有打印出来,因为在相同的上下文中,let不允许重复声明(而且检查是否重复声明发生在“词法解析阶段”) console.log(‘ok’); let n = 12; let n = 13; // Uncaught SyntaxError: Identifier ‘n’ has already been declared console.log(n);
=============================================================================== // 且不论基于什么方式声明的变量,只要在当前上下文中有了,则不允许再基于let/const声明; var n = 12; let n = 12; // Uncaught SyntaxError: Identifier ‘n’ has already been declared */
暂时性死区(浏览器遗留BUG):基于typeof检测一个未被声明的变量,不会报错,结果是undefined
```javascript
console.log(a); // Uncaught ReferenceError: a is not defined
console.log(typeof a); // undefined 暂时性死区
======================================================================
//此法解析阶段报错,优先级高于typeof,避开了暂时性死区
console.log(typeof a); // Uncaught ReferenceError: Cannot access 'a' before initialization
let a = 12;
let 可以解决暂时性死区问题
- 块级私有上下文(作用域)
- 除函数或者对象的大括号之外,如果括号中出现 let/const/function 则会产生块级私有上下文
- 当前块级上下文也只是对let/const/function他们声明的变量有作用
// 这里面没有块级上下文,只有全局上下文
if(1==1) {
var n = 12;
console.log(n); //12
}
console.log(n); // 12
=================================================================================
// 大括号里有let,形成块级上下文
if(1==1) {
let n = 12;
console.log(n); //12
}
console.log(n); // Uncaught ReferenceError: n id not defined
================================================================================
if (1 == 1) {
let n = 12;
var m = 13; //依然是全局的,私有块级上下文对他无效
console.log(n, m); // 12 13
}
console.log(m); //13
console.log(n); //Uncaught ReferenceError: n is not defined */
函数变量提升阶段:
[老版本浏览器] 不论条件是否成立,都要fn 声明+ 定义,而且fn只是全局上下文中的变量
[新版本浏览器] 为了兼容ES3/ES6,规则处理的非常的复杂
- 全局变量提升:如果创建函数的代码出现在”非函数或者对象的大括号中(例如:判断替、循环体、代码块…)”,只会对它进行声明,不进行赋值 =》 function fn;
- 条件成立,代码执行进入到大括号当中,如果大括号中出现了 function xxx(){} ,此时当前大括号会形成一个私有的上下文,私有上下文中的第一件事情也是变量提升,它会把函数进行声明+定义 ```javascript console.log(fn);// [新版本]:undefined [老版本]:函数本身fn(){console.log(‘ok’)} if(1 == 1) { // 私有上下文变量提升: fn = 0x000000; console.log(fn); // [新版本]:函数本身 fn(){console.log(‘ok’)} function fn() { // 代码执行到这的时候,会把私有上下文中,之前对于fn的操作,映射到全局一份 console.log(‘ok’); } fn = 12; console.log(fn); //[新版本]:12 } console.log(fn); // [新版本]:函数本身 fn(){console.log(‘ok’)}
=================================================================================== console.log(fn); {// 和前面的if(1 == 1){} 判断的语句的大括号效果一样 console.log(fn); function fn() { console.log(‘ok’); } fn = 12; console.log(fn); }
**[老版本]:**
- 变量提升:找到所有带var/function的关键字的提前声明或者定义
- 代码执行
```javascript
console.log(fn); // 函数本身 fn(){console.log('ok')}
if(1==1) {
console.log(fn); // 函数本身 fn(){console.log('ok')}
function fn() {
console.log('ok');
}
fn = 12;
console.log(fn); // 12
}
console.log(fn); // 12
[新版本]:
- 变量提升:只是声明了fn->function fn “出现在大括号中”
- 代码执行
块级上下文中没有this、arguments
console.log(fn); // undefined
if(1==1) {
// 私有“块级”上下文,fn做变量提升-> 声明+定义, 且“映射”给全局一份
console.log(fn); // 函数本身 fn(){console.log('ok')}
function fn() {
console.log('ok');
}
fn = 12;
console.log(fn); // 12
}
console.log(fn); // 函数本身 fn(){console.log('ok')}
debugger 断点调试F10/F11
F11 step in
F10 step over