js代码是按顺序执行的吗?
fn()
console.log(name)
var name = "qq"
function fn(){
console.log('fn')
}
//fn
//qq
如上所示:变量(var/function)可在未声明定义前使用。
- 当响应头content-type:application/javascript时,浏览器对js字符串进行词法解析。
- 在词法解析阶段,let/const声明的变量会明确必然存在,所以此变量不可在声明前使用,称为 “暂时性死区”,不存在变量提升。
js执行流程
-一段js代码要经过编译阶段与执行阶段
- 编译阶段生成执行上下文与可执行代码
-
- 执行上下文是代码的运行环境包括this,变量环境,词法环境等
- 在编译阶段,var/function会被存放在变量环境中,默认值设置未undefined。在执行阶段去变量环境中查找。
变量提升
在js执行阶段,把var变量的声明部分与函数声明+定义提升到代码开头行为,会给var变量设置默认值undefined。
- function在变量提升阶段已经声明+定义处理过,可以在声明前执行。
- var 声明操作已经处理,但是赋值操作没有
- if中无论条件是否成立,var都进行变量提升
- 判断体中出现function,老版本:函数声明+定义,新版本:只声明+不定义
- 函数表达式声明函数 const fun = function(){}
- key in obj 判断一个对象是否存在某个属性,会沿着对象的原型链寻找所有的键值。
obj.hasOwnProperty(key)则只会寻找对象自身的属性(不包括原型链)。
块级作用域
- 作用域(scope):变量与函数的可访问范围。
- es5只有全局作用域以及函数作用域,ES6引进块级作用域。
- 除函数和对象的大括号外{例如:判断体,循环体}
if(true){ }-如果在大括号中出现了let/const/function/class等关键词声明变量,产生一个块级上下文。var不受影响。
function
- 在新版本浏览器中,判断体中出现的function,不论条件是否成立,都只声明不定义。
- 判断体中出现function产生块级上下文,对function声明+定义(即在全局声明过,也在块级声明)
- 当执行到函数function(){}时,本行以上的代码对函数的所有操作,同步给全局一份 但是本行以后对函数的操作,对全局没有任何影响,只对块级上下文有效。
// 产生块级作用域,此时函数在全局只声明
console.log(afn) //undefined
if(true){
// 块级作用域声明+定义
console.log(afn) //ƒ afn(){}
// 对函数的操作同步到全局一份
function afn(){
}
// 此后对于函数的操作与全局无关
afn = 1
console.log(afn) // 1
}
console.log(afn) //ƒ afn(){ }
(let /const)与 var
- let 不存在变量提升,不允许在定义之前使用
- let 不允许重复声明(不论基于何种方式声明过这个变量)
- 全局上下文中,var/function 是给window(GO)设置的全局属性,基于let声明的变量是放在VO(G)中,与全局没有任何关系
- let 会产生块级作用域
- let 存在暂时性死区 不允许在定义之前使用
- const 在声明时必须赋值
- const 后期不允许改变指针指向
const obj = {n :1} obj.n= 8
ES6如何做到变量提升与块级作用域?
- let与const声明的变量会放入词法环境中。在词法环境的内部也维护了一个小型栈结构。
- 块级作用域就是通过词法环境的栈结构来实现了,而变量提升通过变量环境来实现。