作用域和作用域链
作用域:
函数执行会形成一个私有作用域(栈内存),为代码执行提供一个环境
闭包
- 形成一个私有作用域,使里面的私有变量不受外部影响
- 函数执行,有一个地方可以把变量存储起来,以后想要使用的时候可以拿出来
全局变量
全局对象是最顶层的对象,在浏览器环境指的是window对象。在ES5中,全局对象的属性与全局变量是等价的。
私有变量
在私有作用域中,只有一下两种情况是私有变量
- 声明过的变量(带VAR/FUNCTION)
- 形参也是私有变量
剩下的都不是自己私有变量,都需要基于作用域链的机制向上查找
var a = 12, b = 13, c = 14;
function fn(a){
console.log(a, b, c);
var b = c = a = 20;
console.log(a, b, c);
}
fn(a);
console.log(a, b, c);
-> 12,undefined,14
-> 20,20,20
->12,13,20
fn(a)中: a(形参),b(VAR定义)为私有变量,a,b的改变不影响外部的a,b。c为外部变量,c改变会影响到全局下的c也改变
暂时性死区
基于LET创建变量,会把大部分{}当做一个私有作用域(类似函数的私有作用域),在这里也是重新检查语法规范,看一下是否是基于新语法创建的变量,如果是按照新语法规范来解析
var a = 12;
if(true){
console.log(a);
let a = 13;
}
-> Uncaught ReferenceError: a is not defined
使用LET创建变量,未执行到创建语句时,使用变量会报错。
在原有浏览器渲染机制下,基于typeof等逻辑运算符检测一个未被声明过的变量,不会报错,返回undefined
console.log(typeof a);
-> undefined
如果当前变量是基于ES6语法处理,在没有声明这个变量的时候,使用typeof检测会直接报错,不会是undefined,解决了原有的JS的死区问题
console.log(typeof a);
let a = 12;
-> ReferenceError: Cannot access 'a' before initialization,无法在初始化之前访问’a‘
作用域链查找
当前函数执行,形成一个私有作用域A,A的上级作用域是谁,和他在哪创建(定义)的有关系,在哪创建,他的上级作用域就是谁。
var num = 12;
function fn(){
var num = 120;
return function(){
console.log(num);
}
}
var f = fn();
f();
function(){
var num = 1200;
f():
}()
-> 120
-> 120
ARGUMENTS
arguments:参数集合
arguments.callee:函数本身
arguments.callee.caller:当前函数在哪执行,caller就是谁(记录的是他执行的宿主环境),在全局下执行CALLER的结果是null