js作用域可以简单理解两句话。由上到下,由内到外
(一)预解析
我们来看一段代码
alert(a); var a = 2;
运行结果是undefined。在使用var声明变量但未对其加以初始化时,这个变量的值就是undefined。即a = undefined
function a() { console.log(1); } alert(a);
运行结果:
在预解析阶段JS 解析器 会找关键字var,function,变量等。
这时存入的是 一段代码块 ,即 a = function a() {
console.log(1);
}
在全局作用域中遵循一个简单规则 由上而下 ,在看一段代码,猜一猜结果吧
alert(a); function a (){ alert(4); } var a = 1; alert(a); function a (){ alert(3); } alert(a);
结论:JS 的预解析遇到重名的只留一个, 变量和函数重名了,就只留下函数
(二)执行环境及作用域的概念
执行环境定义了变量或函数 有权访问 的其他数据,决定了它们各自的行为。每个执行环境都有一个与之相关的 变量对象 。环境中定义的所有变量和函数都保存在变量对象中。某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁。
每个函数都有自己的执行环境。
fn1执行完毕后函数的执行环境被销毁,在函数内声明的变量a也随之销毁。
原谅我一直停留在小学时期的画图水平吧~~
当试行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。
到这里插一句话,像我上图的例子里这样执行的函数都是同步滴~~同步任务在执行栈中~~推荐阅读阮一峰大神的JavaScript 运行机制详解:再谈Event Loop
www.ruanyifeng.com/blog/2014/10/event-loop.html
(三)作用域链
当代码在一个环境中执行时,会创建一个作用域链。作用域链可以保证对执行环境有权访问的所有变量和函数的 有序访问 。作用域的前端始终都是当前执行的代码所在环境的变量对象。作用域链中的下一个变量对象来自包含(外部)环境。作用域链的最后一个对象始终是全局执行环境的变量对象。即作用域链遵循 由内到外 的简单规则
现在把我那张小学生水平的图稍作改动
fn1的作用域链,开始是fn1的变量对象,然后是来自包含环境的变量对象,在这里是全局变量对象。
fn2执行时,执行a(),遇到arg1会顺着作用域链寻找arg1,会先从函数a变量对象中寻找arg1,没有就去作用域链上的下一个变量对象fn2的变量对象上寻找,没有就继续作用域链上下一个变量对象全局变量对象中寻找,这里找到了arg1 = true.
总结一下,内部环境可以通过作用域链访问所有外部环境,但外部环境不能访问内部环境中的任何变量或函数。
(四)没有块级作用域
在JavaScript中没有块级作用域。
嘿嘿==,关于这个问题只要记住这句话就够了~~额……当然不会就说这么一句话,不来点干货我都不好意思==
在其他类c语言中,由花括号{}封闭的代码块都有自己的作用域,但是 js没有块级作用域 !!!
如果存在块级作用域应该报错,因为a是一个局部变量,在全局是找不到a的。
但是运行结果a = 9,所以不存在块级作用域。
(五)this
(六)call
转载请注明:苏demo的别样人生 » JavaScript作用域学习笔记