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

第一次写博客,原本是学习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
相关文章
相关标签/搜索