var 是es5的变量声明
var变量 i 在循环的每次迭代中都被共享
由于存在变量提升 共享变量
导致外部引用 就是循环以后的结果
修正这个问题,开发者在循环内使用立即调用函数表达式(IIFEs),以便在每次迭代中 强制创建变量的一个新副本

(function(){})()
var funcs = []; 
for (var i = 0; i < 10; i++) {

funcs.push(

function() { console.log(i)}

);

}

funcs.forEach(

function(func) {

func(); // 输出数值 "10" 十次

}

);

let与const是为了解决没有块级作用域的问题
var声明的变量会沿着作用域链从里到外的获取

function a(){
var b=1;
(function(){
console.log(b);//1
for (var i=0;i<3;i++) {

}
})();
//for (var i=0;i<3;i++) {
//}
console.log(i) // i is not defined
}
a();

从上面可以看出以前我们使用匿名函数来模仿块级作用域
让if或者for之类的运行环境不处于全局变量
b等于1就可以知道 var声明变量,作用域链就会从内到外获取变量

var存在变量声明 可以先使用再声明 会说undefined 在严格模式报错

let与const只在块级作用域有效 不会沿着作用域 可以嵌套重复变量名使用
必须要先声明再使用 不然会报错 出现暂时性死区
因为在进入块级作用域起 变量就需要先声明才能使用

{
let a=1
{
let a=2
}

}

由于var与函数声明一样存在提升 都会放在最前面 所以一般不会报错

const 变量 在声明基本数据类型的时候 string number null undefined
boolean会存储在内存里面
而声明object 对象或者数组 复杂的引用数据类型 会存储在堆里面 用一个指针调用变量
不可改变的是指针的地址 而不是数据

const f={
}
f={}// invalid assignment to const 'f' 对f的无效赋值
var f={}
f={}//不会报错

所以如果是基本数据类型就是一个常量 不可变;
函数执行在执行栈 因为避免单线程的同步 让网页无响应 通过异步解决
出现微任务与宏任务让异步更加细化

全局对象
window global 不同环境不一样 采用this 来动态获取或改变指向
使用普通函数(包含函数声明与函数表达式)动态改变
箭头函数是维持作用域的this保持上下文一致