本篇内容是基于你不知道的javaScript上卷以及自认为是重点的内容,比较基础,如有不对。欢迎各位大佬指正
关于javaScript的历史我这里就略过了,有兴趣的小伙伴可以去你不知道的javaScript上卷书籍或者pdf或度娘自行观看
ok,进入主题
1=> 作用域
几乎所以的编辑语言最基本的功能之一 —可储存变量持有的值,并且可对值进行访问或修改
(储存,访问,修改等,这种能力,你可以理解为状态 ,状态让程序可突破和扩展,否则,只能做一些简单的任务),
但是,这些变量住在哪里,值在哪里?它们储存在哪里,重点是,怎么找到它们?这些问题说明需要一套设计良好的规则来存储变量。并且之后可以方便的找到这些变量,这套规则被称为作用域
那么问题A是:
这些变量住在哪里,值在哪里?它们储存在哪里,重点是,怎么找到它们?
(内存图)
答:上图基本的回答了问题A抛出的问题。至于引用指向,值类型等问题。后面会另开文章解答,否则会跑偏本题(作用域),内存中的栈堆池也是分大小的哦。
ok,问题A解决,虽然和作用域没什么关系,但至少我知道问题A的答案a!!
这里需要讲到 =》JS的解析过程
编译:预处理,在这一过程中,JS解释器完成对JS代码的预处理,(词法分析、语法分析)
运行:JS是一种解释型语言,所谓解释型是指代码在执行时被解释器一行一行动态编译和执行,而不是执行前完成编译,即边编译边执行,
执行期:JS引擎按着作用域机制来执行,JS的变量和函数作用域是在定义时决定的,而不是执行时才决定的,所以JS解释器只需要通过静态分析就能确定每个变量和函数的作用域,这种作用域称为静态作用域,如执行时才决定的,这种叫做动态作用域
(如不理解JS解释器是什么的同学,送你们- JavaScript运行环境,宿主环境,
链接:https://www.cnblogs.com/sniper007/archive/2011/10/27/2226270.html
链接:http://blog.csdn.net/chenxianru1/article/details/78470101?locationNum=1&fps=1
)
当然了。js的解析过程其实不单单只有这些的,例如性能的优化等,这里只是指出大纲,复合本篇的部分内容
问题B:为什么要讲到解析过程?
答:因为编译时,词法分析中会延伸出词法作用域
2=> 词法作用域 (助你理解闭包和声明提升)
①:故名思意,词法作用域就是定义在词法阶段的作用域,换句话说,就是你在写代码时。把变量或函数或语句块写在哪里来决定的,保存作用域不变(大部分情况是这样。也有欺骗词法作用域的方法,但不再本讲解内。也不建议去了解)(闭包就是基于词法作用域书写代码时所产生的自然结果)
②无论函数在哪里被调用。如何被调用,它的词法作用域都只由函数被声明时所处的位置决定 (闭包的本质=词法作用域和函数当作值传递。)
分析3步
第一步:先分析参数
第二步:再分析变量声明
第三步:分析函数声明
具体步骤
0: 函数(变量)在运行的瞬间,会生成个空的 Active Object (活动对象,注意,是个对象)。下简称AO
1: 函数接收形参参数,添加到AO的属性,并且这个时候值为undefine,即AO.age=undefine
1.2:接收实参,添加到AO的属性,覆盖之前的undefine 即AO.age=18
2: 分析变量声明(注意这里。是声明)。如var age;; (若没有变量var age该声明。跳过。找到函数var age该声明)
如果中AO还没有age属性,则添加AO属性为undefine,即AO.age=undefine
如果AO上面已经有age属性了,则不作任何修改 还是var age=18
3: 分析函数声明
如果有function age(){}把函数赋给AO.age ,覆盖上一步分析的值 既AO.age=function age(){}
function func(age) {
console.log(age); 函数 function age() 声明提前,函数优先度大于变量
var age = 25;
console.log(age); //25
function age() {}
console.log(age); //25
}
func(18);
记住以上。词法作用域也就没什么神秘
3=> 函数作用域
全局作用域和局部作用域
简单来说。window下,函数A内附属有变量b或函数c,则为局部作用域,函数A之外的,则为全局作用域。对于变量的查找。都是由内向外的,这个比较简单,就不做过多讲解
4=> 块级作用域
对于部分新接触javaScript的朋友来说。他们似乎看到if/switch/while/for/do等。这些含有{}的关键字,例if(){}else{}.for(){},,觉得,咦。这一块一块的。就是块级作用域的。没毛病啊
比较遗憾。在es6之前。javaScript是没有块级作用域的。以上的那些关键字。其实是语句,语句块,例如:条件语句(if/switch),循环语句(while/for/do),强制跳转语句(break/return/throw)等。es6的let关键字,有兴趣的可以去了解下
5=> 作用域嵌套
emmmmm,这个嘛,函数A里面写个函数B。这就是嵌套了,查找也是由内向外的
6=> 声明提升(也叫声明提前,一个意思)
先有鸡?先有蛋?猜对了给你金坷垃
看完前面的一些概念,应该对作用域比较了解了把,简单一句总结:任何声明在某个作用域内的变量,都将附属于这个作用域
例:var a=2;
词法分析再度来袭!
在前面词法作用域说过了。这里我们看,觉得就是一句var a=2,然而,在JS解释器来看,是两个完全不同的,单独的声明
var a=undefined =》词法分析期
a=2 =》执行期,赋值操作
换个例子。
a=2;
var a;
在词法分析期,var a声明会被提升到该作用域的最顶层,赋值或者其他运行逻辑会留在原地
问题来了。如果我写的函数和变量同名,那么谁是最顶层呢?嘿嘿,看看前面的词法作用域例子就知道了
说到声明提升,或许要说说函数和函数表达式的区别:
foo()
function foo(){}=》这个为函数声明 没毛病 也可以执行
foo()
var foo=function bar(){} =》这就是表达式, 变量foo持有函数bar,在声明提示中var foo=undefined,undefined无法调用啊,所以,会报错