JavaScript学习----------变量的声明和赋值、预编译、作用域链和闭包
变量的声明和赋值、预编译、作用域链和闭包
1.变量的声明和赋值
var x = 1 先声明,后赋值。
es6定义了let关键字。替代var声明一个块级作用域的变量。
常量:const来定义常量。const和let都有块级作用域的特点。
解构赋值:var [x,y,z] = ['a','b','c']
aa = 1 不会报错。和预编译那有关。其实是window.aa = 1。这个不参与预编译。预编译只找有var声明的。
例如:
console.log(xxx) -----------undefined
var xxx = 5
console.log(xxx) ------------ 5
console.log(xxx) -----------报错
xxx = 5 ------------------------未参与预编译
console.log(xxx) ------------ 5
2.预编译
JavaScript引擎的三大步骤:
预编译(第一次扫描)
解释执行(第二次扫描)
预编译----脚本
脚本的预编译:
1.没有var的变量,都不是变量声明,全部认为是window的全局变量,不参与预编译。
2.即使在函数中,aa = 5 也是全局变量,在运行时,而不是定义时。
3.脚本中,所有变量声明,在脚本预编译阶段完成,声明与实际的书写位置无关。
4.脚本中,所有函数声明,在脚本的预编译阶段完成,所有函数的声明与实际书写位置无关。
5.脚本中,如果函数和变量重名,那么函数将覆盖变量。
6.脚本中,只有函数能覆盖变量,变量无法覆盖函数。
7.脚本中,后面的函数声明会覆盖前边的函数声明,并且忽略参数。(忽略重载)
函数的预编译-----函数调用
预编译除了发生在脚本第一次运行以外,还发生在函数调用的阶段。
1.函数中,所有变量声明,在函数的预编译阶段完成,所有变量的声明与实际的书写位置无关。
2.函数中,所有函数声明,在函数的预编译阶段完成,所有函数的声明与实际的书写位置无关。
3.函数中,如果变量和函数重名,那么函数将覆盖变量。
4.函数中,只有函数能覆盖变量,变量无法覆盖函数。
5.函数中,后边的函数声明会覆盖前边的函数声明。
6.当函数预编译后,遇到需要访问的变量和函数,优先考虑自己AO中定义的函数和变量。如果找不到,才会在其定义的上一层AO中寻找,直到到达GO。
例题:
function test(x,x){
console.log(x);
x=5;
console.log(arguments);
function x(){}
}
test(12,13)
GO:
test:function
test-AO:
arguments:[12,5]
x-和arguments[1]绑定:5
输出:function、[12,5]
作用域链和闭包:
1.执行环境和作用域链:
执行环境:execution context 简称ec,它定义了执行期间可以访问的变量和函数。也就是说它是变量和函数的表。
全局执行环境:global object----GO----window,从见到代码开始创建,到网页关闭销毁。
函数执行环境:activation object ------AO,从函数开始调用开始创建,到函数结束时销毁。
作用域链:函数被创建时作用域中对象的集合:scope chain,是AO和GO构成的链。每个函数都有。作用域是私有属性 ,只能有js引擎去访问。
生成作用域链:每个函数在定义(函数声明和函数表达式)时都会拷贝其父亲函数的作用域链。
在函数被调用时,生成AO然后将AO压入作用链的栈顶。
闭包的作用:
模块化操作,避免污染共有变量。
闭包的习题: