第一次写博客,本来是学习jQuery遇到闭包问题,发现并没有理解闭包,发现闭包牵扯的知识点太多。复习了一遍(发现自己该记住的全忘了)写在博客里,自己也是小白,希望大神们指点迷津,必将感激不尽。
我们知道JavaScript有两个特点:单线程,解释型语(翻译一行,解释一行)。但其实翻译一行,解释一行是最后一部才这样做,在这之前会有一个语法分析:通篇扫描看有没有语法错误,但不执行,通篇扫描之后,会进行 预编译 然后 -->解释一行,执行一行。这就是我们所说的js运行三部曲:语法分析     预编译     解释执行
 
没错,预编译开始啦!
test()                        //VM129:1 Uncaught ReferenceError: test is not defined
 
console.log(a)         // VM118:1 Uncaught ReferenceError: a is not defined
 

test();     //456

function test(){

  console.log(456);
};
 
console.log(a);      //undefined
var a = 123;
上面四段代码当我们执行前两个的时候报错,浏览器告诉我们 test 和 a 没有被定义,而后两段代码并没有报错,这就是预编译。
在学习预编译的时候我们总是记住一句话:函数声明整体提升,变量    声明提升。也就是说预编译会把整个函数放在最最前面。而变量 声明提升是什么意思呢?
var a = 123;其实是变量声明和赋值的两个过程;1)var a;     2)a = 123;预编译只把声明提升在最前面
 
console.log(a); //undefined
var a = 123;
--->
var a;
console.log(a); //undefined
a = 123;
--------------------------
test(); //456
function test(){
console.log(456);
}
--->
funciton test(){
console.log(456);
}
test(); // 456
但是光记住这两句话并不能解决所有的问题。
看一下下面的
console.log(a);
function a(){
}
var a = 123;
想一下打印的是什么?
居然是
ƒ a(){
}
再看看下面的更复杂的
console.log(a);
function a(a){
var a = 234;
var a = function(){
}
a();
}
var a = 123;
这个打印出来是什么呢?
ƒ a(a){
var a = 234;
var a = function(){
}
a();
}
这是为什么呢?
下面来讲一下预编译: imply global 暗示全局变量:即任何变量。如果变量未经申明就赋值,此变量就为全局对象(window)所有。
a = 123;如果 var a = b = 123;在函数里a就是函数内部变量,b则是全局变量。
一切声明的全局变量,全是window的属性(window 就是全局的域):var a = 123;-----> window.a = 123;
使用var声明的变量会自动被添加到最接近的环境中。
预编译发生在函数执行的前一刻。
预编译四部曲:
1.创建AO对象/活动对象(activation object)(执行期上下文)
2.找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
3.将实参值和形参统一
4.在函数体里面找到函数声明,值赋予函数体
由此我们便知道上面的那两个例子打印的为什么是那样的。
下面我们来看下更复杂的
function fun(a) {
  console.log(a);
  var a = 123;
  console.log(a);
  function a() { }
  console.log(a);
  var b = function () { }
  console.log(b);
  function d() { }
}
fun(1);
-->
1.生成AO对象
AO{
}
2.找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
AO{
  a: undefined;
  b:undefined;
}
3.将实参值和形参统一
AO{
  a: 1;
  b:undefined;
}
4.在函数体里面找到函数声明,值赋予函数体
AO{
  a: function a(){};
  b:undefined;
  d:function(){}
}
预编译结束
函数执行 AO就像一个创库一样,函数执行期间里面的仓库也会变化
AO{
  a: function a(){};
  b:undefined;
  d:function(){}
}
function fun(a) {
  console.log(a);      // ƒ a() { }
  var a = 123;
  console.log(a);      //123
  function a() { }
  console.log(a);      //123
  var b = function () { }
  console.log(b);      //ƒ () { }
  function d() { }
}
--------------------------
function test(){
  console.log(b);
  if(a){
    var b = 100;
  }
  console.log(b);
  c = 234;
  console.log(c);
}
var a;
test();
a = 10;
console.log(c);
预编译
全局GO
GO{
a:undefined;
test:function test(){}
}
AO{
b:undefined;
}
------------
执行函数
GO{
a:undefined;--->10
test:function test(){}
c:234
}
AO{
  b:undefined;
}
function test(){
  console.log(b); //undefined
  if(a){
    var b = 100;
  }
  console.log(b); //undefined
  c = 234;
  console.log(c); //234
}
var a;
test();
a = 10;
console.log(c); //234
 
作用域 作用域链
function test(){};
我们知道一个函数就像一个房子一样,这个房子形成单独的域,里面能看到外面的,外面的看不到里面的,我们可以把函数生成的空间叫做作用域那这个作用域到底是什么呢?
这个作用域是因函数产生而产生的,每个对象都有属性和方法,函数(function)也是一种特殊的对象,函数可以有test.name test.prototype ...这些是可以访问的
还有一些属性是不可以访问的隐式属性仅供JavaScript引擎处理。 比如[[scope]]:指的就是我们所说的作用域链,其中存储了执行期上下文的集合。
为什么时集合呢?作用域链:是[[scope]]中所存储的执行期上下文的集合,这个集合呈现链式连接,我们把这种连接叫做作用域链。
作用域链本质上是一个指向变量对象的指针列表,他只是引用,但不包含实际变量对象。
test.[[scope]]这里面存的就是作用域。系统会根据内部的原理去定期调用scope。
上面提到了执行期上下文(前面作用域也提到的AO对象就是这个):当函数执行的前一刻的时候,会创建一个称为执行期上下文的内部对象(AO activation object)。一个执行期上下文定义了一个函数执行时的环境
函数每次执行时对应的上下文都是独一无二的 test(); test();一样的函数但是执行期上下文并不相同,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,他所产生的执行上下文会销毁。
看一下下面的例子
function a(){}
var glob = 100;
a();
 
当a函数被定义 a.[[scope]]---> 0:GO{} 因为a函数在全局作用域里,所以他的第一位存的时GO
当a执行执行 a.[[scope]]---> 0:AO{}
1:GO{}
----------------------------------------------
function a(){
  function b(){
    function c(){}
    c();
  }
  b();
}
a();
a defined a.[[scope]]  ---> 0 : GO
a doing a.[[scope]]   ---> 0 : a AO
             1 : GO
b defined b.[[scope]]  ---> 0 : a AO
            1 : GO
b doing b.[[scope]]   ---> 0 : b AO
            1 : a AO
            2 : GO
c defined c.[[scope]]  ---> 0 : b AO
            1 : a AO
            2 : GO
b doing c.[[scope]]   ---> 0 : c AO
            1 : b AO
            2 : a AO
             3 : GO

JavaScript 之 预编译 作用域,作用域链的更多相关文章

  1. JavaScript 预编译与作用域

    JavaScript 预编译与作用域 JavaScript 预编译的过程和作用域的分析步骤是 JS 学习中重要的一环,能够帮助我们知道代码的执行顺序,更好理解闭包的概念 预编译 JavaScript ...

  2. 预编译And作用域链

    首先要理解什么是预编译: 预编译就是在JS执行前的一瞬间创建一个AO对象,这个创建AO的过程叫做预编译. console.log(a) var a = 1; function c(b){ b = 10 ...

  3. javascript的预编译和执行顺序

    原文:javascript的预编译和执行顺序 最近在复习javascript的事件处理时发现了一个问题,然后也是我来写javascript的预编译和执行顺序的问题 代码: 代码一<html> ...

  4. 一步一步的理解javascript的预编译

    首先,我们要知道javascript是单线程.解释性语言.所谓解释性语言,就是翻译一句执行一句.而不是通篇编译成一个文件再去执行. 其实这么说还没有这么直观,读一句执行一句那是到最后的事了.到JS执行 ...

  5. JavaScript的预编译和执行

    JavaScript引擎,不是逐条解释执行javascript代码,而是按照代码块一段段解释执行.所谓代码块就是使用<script>标签分隔的代码段. 整个代码块共有两个阶段,预编译阶段和 ...

  6. 还原真实,javascript之预编译 / 预解析

    今天在群里吹水时,有群友提出一个问题.我一看很简单,就立马给出了答案:因为存在变量提升,所以输出undefined.本以为无人反驳,可确招来口诛笔伐.作为写实派的我,一贯以来坚持真实是我的使命,岂能容 ...

  7. JavaScript之预编译

    javascript是一种解释性弱类型语言,在浏览器中执行时,浏览器会先预览某段代码进行语法分析,检查语法的正确与否,然后再进行预编译,到最后才会从上往下一句一句开始执行这段代码,简单得来说可以表示为 ...

  8. Javascript的"预编译"思考

    今天工作需要,搜索下JS面试题,看到一个题目,大约是这样的 <script> var x = 1, y = z = 0; function add(n) { n = n+1;  } y = ...

  9. JavaScript函数——预编译

    四部曲 创建AO对象 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined. 将实参值和形参值统一 在函数体内找函数声明,值赋予函数体. 权重按顺序依次增加.以下例子即可体现上述规则 ...

随机推荐

  1. python练习小文章-文本爬虫

    一入“程”门深四海...... 有学习就得有练习,我来练一个文本爬虫,代码直接写到下面,抓取的是网页图片,简单好学,适合新手练习. 话不多说直接上干货! 1. 目标网址:https://www.jik ...

  2. Spring _day01_下载、概述、监听器

    Spring:SE/EE开发的一站式框架. ​ .一站式框架:有EE开发的每一层解决方案. ​ . WEB层 :SpringMVC ​ . Service层 :Spring的Bean管理,Spring ...

  3. 关于visual studio的一些日常总结

    一.常用的VS快捷键 批量注释:ctrl + k ctrl + c 批量解除注释:ctrl + k ctrl + u 转到声明:ctrl + F12 查找:ctrl + F 添加断点:F9 逐过程调试 ...

  4. Python2.0 与 3.0 的区别

    Python 2.0 =默认编码=ASSIC=不支持中文 Python 3.0 =默认编码=UNICODE=默认支持中文   In summary : Python 2.x is legacy, Py ...

  5. rtp传输音视频(纯c代码)

    参考链接: 1. PES,TS,PS,RTP等流的打包格式解析之RTP流 https://blog.csdn.net/appledurian/article/details/73135343   2. ...

  6. (一)java异常处理的几个问题

    1.java中两种异常? 答:java中存在两种异常:受检查(checked)异常和不受检查(unchecked)异常.不受检查的异常不需要在方法或者构造函数上声明,就算是方法或是构造函数会发生这样的 ...

  7. python笔记27-time模块

    import datetime, time#一种是时间戳.一种是格式化时间.一种是时间元组# print(time.timezone) # 和标准时间相差的时间,单位是sprint(int(time. ...

  8. 【leetcode198 解题思路】动态规划

    动态规划 https://blog.csdn.net/so_geili/article/details/53639920 最长公共子序列 https://blog.csdn.net/so_geili/ ...

  9. Beta阶段冲刺二

    Beta冲刺二 1.团队TSP 团队任务 预估时间 实际时间 完成日期 对数据库的最终完善 120 150 12.2 对学生注册功能的完善--新增触发器 150 140 11.29 对教师注册功能的完 ...

  10. IDEA新建项目时,没有Spring Initializr选项

    换了台新电脑,然后重新安装了Intellij IDEA,创建spring boot项目的时候找不到Spring Initializr选项了. 然后百度了下,发现有前辈做出了回答,就复制存到了自己随笔里 ...