var的变量提升和let的
//es3/es5
//变量提升:当栈内存(作用域)形成,JS代码自上而下执行之前,浏览器首先会把所有带var和function关键字的进行提前的
//声明或定义.这种预先处理机制称之为变量提升。
//声明(declare):var a或function sum
//定义(defined):a=12 也就是赋值
//变量提升阶段:
//带var的只声明未定义
console.log(a)//undefined var a = 12; function b(arr){//变量提升阶段function就完成了声明和赋值,浏览器会在全局作用域声明一个b,然后再形成一个堆内存里面 //是函数体里面的代码字符串。这个堆内存会有一个16进制的地址,而全局里面声明的那个b就会指向这个地址 //因为函数在变量提升阶段就完成了声明和赋值,所以在代码执行阶段在遇到b这个函数就不会在重复声明赋值,就会直接跳过 for(let i=0;i<arr.length;i++){ console.log(i) } } //跳过后就会执行下面这个函数调用,传了一个数组进去。 //而执行一个函数也就是形成了一个私有栈内存。当私有的作用域形成后也不是立即代码执行,而是先进行变量提升(变量提升前,先形参赋值) b([1,2,3,4]) //在ES3和ES5语法规范中,只有全局作用域和函数执行的私有作用域(栈内存),其他大括号不会形成栈内存
//带var与不带var
//在全局作用域下声明一个变量,也相当于给window全局对象设置了一个属性,变量的值就是属性值(私有作用域下声明的私有变量
//和window没有关系)
//带function的声明和赋值都完成了
//变量提升至发生在当前作用域(例如:开始加载页面的时候支队全局作用域下的进行提升,因为此时函数中存储的都是字符串)
//在全局作用域先声明的函数或者变量是‘全局变量’,同理,在私有作用域下声明的变量是‘私有变量’[带var和function才是声明
console.log(i)//undefined console.log(window.i)//undefined console.log('i' in window)//true 在变量提升阶段,在全局作用域中声明了一个变量i,此时就已经把i当做属性值赋值 //给了window了,只不过此时还没有给i赋值,默认是undefined // in? :检测某个属性是否隶属于这个对象 var i = 9//变量值修改window的值也跟着修改 console.log(i)//9 console.log(window.i)//9 window的一个属性名为i i=13 console.log(window.i)//13 window.i=14 console.log(i)//14 重点:全局变量和window的属性存在‘映射机制’,就是有一个改变另一个也跟着改变
//不带var 不带var的本质是window的属性
//console.log(j)//j is not defined 这里的J是按照变量的来识别的 //console.log(window.j)//undefined 这里是按照window的属性来识别的,因为对象没有某一个属性返回的就是undefined //console.log(window.j)//false 不存在这个属性 j=10// 这里不带var 就相当于给window加了一个属性叫j,值是10 console.log(j)//10 console.log(window.a)//12 // var q =10, // s =11 //这样写s是带var // var q = s =11 // 这样写不带var //在私有作用域中带var和不带var也有区别:带var在私有作用域变量提升阶段都声明为私有变量和外界没有任何关系 //不带var 不是私有变量,它会想它的上级作用域查找,看它是否是上级的变量,不是继续向上查找,一直找到window为止 //这种查找机制叫‘作用域链’ //console.log(n,m)//undefined undefined var n =13; m =13; function fn(){ console.log(n,m)//变量提升阶段先var了一个n所以是 undefined 但是m不带var,向上级查找所以m是13 ; var n = m = 14//此时都是14 console.log(n,m)//14 14 } fn() console.log(a,m)// 这里的a是全局的所以是13,b在函数里被重新赋值所以是14
//在私有作用域中如果向上级查找变量到window的时候发现window也没有这个属性时又是怎么做的呢?
function f(){ b = 13 console.log('b' in window)//true 在作用域查找的过程中,如果找到window也没有这个变量,相当于给window设置了 //了一个属性b console.log(b)//13 } f() console.log(b)//13
//只对等于号左边进行变量提升
fnn()// fnn is not a function sun()//2 var fnn = function (){//函数表达式声明 因为是用var关键字声明在变量提升阶段只提升了等号左边的fnn, //但是并没有定义或赋值,所以在上面调用时报错 console.log(1) } fnn() function sun (){//普通方式声明的函数在 变量提升阶段就已经声明和定义完毕 所以上面可以直接执行 console.log(2) } sun()
//条件判断下变量提升
console.log(z) if(1===2){//在当前作用域下,不管条件是否成功都要进行变量提升, //带var的还是只是声明 //带function的在老版本浏览器渲染机制下,声明+定义都处理,但是为了迎合es6中的块级作用域,新版浏览器对于函数 //(在条件判断中的函数),不管条件是否成立,都是先声明,没有赋值。 var z = 10 } console.log(z) if(1===1){ console.log(fs)//函数本身:当条件成立,进入到判断体中(ES6中它是以个块级作用域)第一件事并不是变量提升, //先把fs声明并定义,也就是判断体中代买执行前,fs就已经赋值了 function fs(){ console.log('ok') } } console.log(fs)//函数本身
//ES6中let创建的变量不存在变量提升。不允许重复定义 暂时性死区
//切断了全局变量和window属性的映射机制
console.log(a)//a is not defined let a =12 console.log(window.a)//undefined console/log(a)//12