预解析与作用域
预解析
不是告诉你怎么写代码
遵循代码的执行机制, 怎么才能写出来规范的代码
预: 在所有代码执行之前
解析: 解释, 对代码进行通读并解释
解释的使用方法
1. var 关键字
在代码执行之前会把 var 关键字定义的变量提前声明
2. 声明式函数
会把这个函数名在所有代码执行之前声明, 并且赋值为一个函数
注意: 赋值式函数
var fn = function () {}
按照 var 的规则进行解析
预解析案例
有 变量 的解析
有 声明式函数 的解析
问题: 变量名 和 函数名 重名了该如何去解决
当 函数 和 变量 重名的时候, 以预解析阶段的函数为准
作用域
作用域分为两种,一种是全局作用域,另一种是私有作用域
1. 全局作用域
打开一个页面就是一个全局作用域
全局作用域, 通常值 window 系统
2. 私有作用域(局部作用域)
**只有函数生成私有作用域**
3.作用域的上下级关系
你的函数写在哪个作用域下
你就是谁的子级作用域
作用域的上下级关系干什么用
为了确定变量的使用范围
三个机制
1. 变量定义机制
有 var 关键字
声明式函数
var num
function fn() {}
2. 变量使用机制
你需要拿到某一个变量的值来使用
n++
console.log(abc)
3. 变量赋值机制
一定要有赋值符号
num = 100
num += 100
上图 展示了前面这段代码的作用域链。分级展示不能更好的帮助大家理解作用域的层级。
变量的三个机制
变量的定义机制
一个变量(函数)
在哪一块作用域里面定义
就只能在当前作用域,和下级作用域里面使用
无法在上一级作用域使用
变量使用机制
当你需要使用一个变量(函数)
首先要在自己的作用域内查找, 如果有, 直接使用
如果没有, 取上一级作用域查找, 如果有, 直接使用
如果还没有, 再去上一级查找
直到 window 都没有, 那么就 **报错**
变量赋值机制
当你需要给一个变量(函数名)赋值的时候
会首先在自己作用域内查找, 如果有, 直接赋值
如果没有, 取上一级作用域查找, 有就赋值
还没有, 再去上一级作用域查找, 有就赋值
直到 window 都没有, **把这个变量定义为全局变量, 在进行赋值**
1. 使用 var 的函数作用域声明 在使用 var 声明变量时,变量会被自动添加到最接近的上下文。在函数中,最接近的上下文就是函 数的局部上下文。
注意 未经声明而初始化变量是 JavaScript 编程中一个非常常见的错误,会导致很多问题。 在初始化变量之前一定要先声明变量。
2. 使用 let 的块级作用域声明 ES6 新增的 let 关键字跟 var 很相似,但它的作用域是块级的,这也是 JavaScript 中的新概念。块 级作用域由最近的一对包含花括号{}界定。
let 与 var 的另一个不同之处是在同一作用域内不能声明两次。重复的 var 声明会被忽略,而重 复的 let 声明会抛出 SyntaxError。
let 的行为非常适合在循环中声明迭代变量。使用 var 声明的迭代变量会泄漏到循环外部,这种情 况应该避免。
3. 使用 const 的常量声明 除了 let,ES6 同时还增加了 const 关键字。使用 const 声明的变量必须同时初始化为某个值。 一经声明,在其生命周期的任何时候都不能再重新赋予新值。
const 除了要遵循以上规则,其他方面与 let 声明是一样的。
注意 开发实践表明,如果开发流程并不会因此而受很大影响,就应该尽可能地多使用 const 声明,除非确实需要一个将来会重新赋值的变量。这样可以从根本上保证提前发现 重新赋值导致的 bug。
总结:
JavaScript 解释阶段便会确定作用域规则,因此作用域在函数定义时就已经确定了,而不是在函数调用时确定,但是执行上下文是函数执行之前创建的。执行上下文最明显的就是 this 的指向是执行时确定的。而作用域访问的变量是编写代码的结构确定的。
作用域和执行上下文之间最大的区别是:执行上下文在运行时确定,随时可能改变;作用域在定义时就确定,并且不会改变。
版权声明: 本文为 InfoQ 作者【Jason199】的原创文章。
原文链接:【http://xie.infoq.cn/article/57e99017a249c406eb4f41401】。
本文遵守【CC BY-NC】协议,转载请保留原文出处及本版权声明。
评论