ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

JavaScript 之 预编译 作用域,作用域链

2019-02-22 20:38:46  阅读:236  来源: 互联网

标签:function console log 作用域 JavaScript AO 编译 test var


第一次写博客,本来是学习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

标签:function,console,log,作用域,JavaScript,AO,编译,test,var
来源: https://www.cnblogs.com/jiaobaba/p/10420531.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有