变量:简单来讲就是在特定时间内保存特定值的一个名字而已,因为不存在定义某个变量必需要保存某种数据类型值的规则,因此变量的值及其数据类型能够在脚本生命周期内任意改变,变量可能包含两种不一样的数据类型得值:基本类型值和引用类型值。基本数据类型包括:Undedind、Null、Boolean、Number、String和Symbol(es6新增),同时Boolean、Number、String和Symbol也叫基本包装类型。引用类型:简单来讲,除了全部基本类型剩下的就是引用类型了。可能不严谨,先这样对付看吧。前端
做用域:咱们已经知道了变量的做用其实就是存储值,那么咱们要怎么样才能对值进行访问或者修改?换句话说,这些变量住在哪里呢,更重要的是咱们(程序)要如何找到他们?像莎士比亚说得那样:To be, or not to be: that is the question!因此咱们须要一套设计良好的规则来存储变量,而且能够方便的找到这些变量,这套规则就叫做用域!es6
在了解做用于规则前,咱们先要知道编译原理,即咱们的代码写下以后是怎么工做的。在强类型语言中,程序中要执行一段源代码首先要通过编译,编译过程有三个步骤:编程
一、分词/词法分析。这个过程将字符组成的字符串分解成有意义的代码块,这些代码块被称为词法单元,例如 var a = 2;这段代码一般会被分解成为下面这些词法单元:var、a、=、二、;。空格是否被看成词法单元取决于空格对于这门语言是否有意义。数组
二、解析/语法分析。这个过程是将词法单元数组转换成一个由元素逐级嵌套所组成的表明程序语法结构的树,叫“抽象语法树”(Abstract Syntax Tree,AST)。简单来讲,对于编程语言下的源代码,经过构建语法树的形式将源代码中的代码映射到树中的每个节点上。编程语言
三、代码生成。将AST(抽象语法树)转换为可执行的代码这一过程叫作代码生成。简单来讲就是将 var a = 2;的AST转化成机器能认识的指令,建立一个变量a,而后他的值2储存在a中。函数
比起那些编译过程只有三个步骤的编译器,JavaScript引擎要复杂的多,在语法分析和代码生成阶段有特定的步骤来对性能进行优化,包括对冗余元素进行优化等,具体有哪些步骤,我也不知道,由于编译原理这段内容是摘抄《《你不知道的JavaScirpt 上卷》》书中的原话,哈哈哈,是否是很吃精!!!JS的编译大部分发生在代码执行前的,而且编译完成立刻执行。性能
请看var a = 2;这段代码,正常人会认为这是一句生明,由于语句中没有‘,’或者’。‘等语句分隔符号,可是在JS引擎中认为这里有两个声明:变量生命和赋值生明。首先是词法分析过程,将var a = 2;分解成词法单元,而后语法分析生成抽象语法树,最后执行代码。具体一点说,var a = 2;会分解成var a 和a = 2;当编译器遇到var a,时,编译器会询问做用域是否已经存在一个该名称的变量存于同一个做用域中,若是是则会忽略该生明(es6中新增的let和const状况有点不太同样),若是没有存在,则在当前做用域中生命一个新的变量,命名为a。接下来编译器会为引擎生成运行时所须要的代码,这段代码来处理a=2这个赋值操做。引擎运行时首先会在当前做用域中查找是否有一个叫作a的变量,若是有就赋值,若是没有就继续向上一级做用域查找,若是实在是找不到,找到了做用域顶层全局做用域也找不到,那么就会抛出一个错误。因此变量赋值操做总会执行两个步骤,若是变量未声明则在当前做用域中生名一个变量(严格模式下若是给未声明的变量赋值会报错),而后运行时引擎会在做用域中查找改变量,若是找到了就进行赋值。优化
做用域是怎么造成的呢?简单来说就是执行环境所决定的,每个执行环境都有一个与之关联的变量对象,环境内的全部变量和函数都保存在这个对象中,在全局环境下执行保存在全局的变量对象中叫全局做用域,在函数内的变量保存在函数内部的变量对象构成局部做用域。当代码在一个环境中执行时,会建立变量对象的一个做用域链,做用域链的前端始终都是当前代码所在环境的变量对象中。编译器在查找变量时就是沿着做用域链一级一级地搜索标识的过程,直到全局执行环境也就是全局做用域为止。当一个做用域嵌套在另外一个做用域中,就发生了做用域嵌套,所以在当前做用域中没法找到某个变量时,引擎就会沿着做用域链在外层嵌套的做用域中查找,知道找到该变量或者在做用域链顶端(全局做用域)为止。以下:spa
function foo(a){ console.log(a+b); } var b = 2; foo(2); // 4
这段代码中,引擎首先会在foo函数中问foo的做用域,你见过b吗?foo做用域:没见过,滚犊子。而后引擎沿着做用域链往上爬,爬到了全局做用域中,而后问:全局做用域大哥你见过b吗?全局做用域:嗯 我见过,给你吧。设计
嵌套做用域规则很简单,就是在当前做用域开始,一级一级地向上查找。直到抵达最外层全局做用域,查找过程就会中止!
以前说过,变量在赋值操做前老是会先查找而后再赋值,若是在非严格模式下,查找不到所要赋值的变量,全局做用域中会隐式的建立一个具备该名称的变量并返回给引擎。以下:
function foo(a){ console.log(a+b); b = a; } foo(2); // 4
很久以前写的,好像我是在抄书,照本宣科吗?哈哈