1. 执行上下文环境及做用域前端
(1)执行上下文:执行上下文的定义---在执行代码以前,把将要用到的变量都事先拿出来,有的直接赋值了(this和函数声明),有的先用undefined占个位(变量和函数表达式)。web
处于活动状态的执行上下文环境只有一个。函数每被调用一次,都会产生一个新的执行上下文环境。当执行流进入一个函数时,这个函数的环境就会被推入一个环境栈中。在函数执行以后,环境栈将其环境弹出。即函数执行完以后就会将其执行上下文环境销毁(还有种状况就是闭包,闭包执行完以后,他的执行上下文环境不会被销毁)。浏览器
(2)全局执行环境 是最外围的一个执行环境,在web浏览器中,全局执行环境是window对象。闭包
(3)做用域:函数在定义的时候,就已经肯定了函数体内部自由变量的做用域。js没有块及做用域,除了全局做用域外,只有函数才能建立做用域。做用域最大的用处就是隔离变量,不一样做用域下同名变量不会有冲突。函数
(4)做用域链:做用域有上下级关系,上下级关系的肯定就看函数在哪一个做用域下建立的,当代码在一个环境中执行,会建立变量对象的一个做用域链。当访问变量时,会一级一级向上寻找变量定义,直到找到他。若一直寻找到全局做用域还找不到就会报 'xxx is not defined'的错误。ui
做用域链的用途是保证对执行环境有权访问的全部变量和函数的有序访问。例:this
var num = 1; function changeNum(){ if(num===1){ // 能够在函数内部访问num,是由于能够再做用域链中找到他 num=2; } else{ num=1; } } changNum(); alert(num) // 2
局部环境中开始时会先在本身的变量对象中搜索变量名和函数名,搜索不到的话就搜索上一级做用域链。url
2. 延长做用域链spa
try catch语句的catch块;with语句,这两个语句会在做用域链的前端添加一个变量对象。debug
function buildUrl() { var qs = "?debug=true"; with(location){ var url = href + qs; } return url; }
with 语句接收的是 location 对象,所以其变量对象中就包含了 location 对象的全部属性和方法,而这个变量对象被添加到了做用域链的前端。
with 语句中引用变量 href 时(实际引用的是 location.href),with 语句内部,定义了一个名为 url 的变量,于是 url 就成了函数执行环境的一部分,因此能够做为函数的值被返回。
3. 没有块级做用域
js有做用域,函数做用域,可是没有块级做用域。js除了全局做用域外,只有函数能建立做用域
if 语句 for语句 中的变量声明会将变量添加到当前的执行环境
(1)声明变量
使用 var 声明的变量会自动被添加到最接近的环境中。若是初始化变量,没有用var声明,该变量会自动被添加到全局环境中。
function add(num1, num2) { var sum = num1 + num2; // 这里若是有var声明则是被添加到函数内部执行环境中,因此后面访问不到 return sum; } var result = add(10, 20); //30 alert(sum); //因为 sum 不是有效的变量,所以会致使错误 function add(num1, num2) { sum = num1 + num2; // 这里没有用var声明,sum变量被添加到全局做用域,因此后面能够访问到sum的值 return sum; } var result = add(10, 20); //30 alert(sum); //30
(2)查询标识符
当在某个环境中为了读取或写入而引用一个标识符时,必须经过搜索来肯定该标识符实际表明什么。搜索过程从做用域链的前端开始,向上逐级查询与给定名字匹配的标识符。若是在局部环境中找到了该标识符,搜索过程中止,变量就绪。若是在局部环境中没有找到该变量名,则继续沿做用域链向上搜索。搜索过程将一直追溯到全局环境的变量对象。若是在全局环境中也没有找到这个标识符,则意味着该变量还没有声明。