JS从0开始(五)预编译

108 阅读5分钟

重点:参数默认值、函数声明提升、暗示全局变量、预编译、AO、GO

1.参数默认值

默认值为undefined

function test(a = 1,b){  /形参a赋予一个值1
console.log(a);
console.log(b)
}
test(); /输出1 , undefined; 即形参b的默认值为undefined

更改全局的test(),给a赋值undefined 给b赋值2时:
test(undefined,2) /输出1,2

function test(a = undefined,b){//形参a,b
console.log(a);
console.log(b)
}
test(1,2); /输出12
/argument如果赋值为undefined就去找形参上的默认值;如果形参为undefined,argument就去找实参

总结:形参实参中, 谁不是undefined就选谁

<script>
        function test(a) {//形参a,b
            console.log(a);
            console.log(b);
        }
        test(1, 2); //输出1,以及 ReferenceError: b is not defined
    </script>

总结:如果有实参没有形参就会出错,有形参没有实参就会输出默认值:undefined

但是上述方法(在括号内给形参赋值)低版本浏览器不兼容,它是ES6中的新方法。
方法二:

function test(a,b){
var a = arguments[0] || 1; //如果a不存在就返回1
var b = arguments[1] || 2;//如果b不存在就返回2
console.log(a , b);
}
test();

方法三:

   function test(a,b){
   var a,b;
   if(typeof(arguments[0]) !== 'undefined'){
   a = arguments[0];
   }else{
     a = 1;
   }
   if(typeof(arguments[1]) !== 'undefined'){
    b = arguments[1];
   }else{
    b = 2;
   }
   console.log(a,b);
   }

思路总结

1.如果有实参没有形参就会出错,有形参没有实参就会输出默认值:undefined

2.函数声明提升:

var a;
console.log(a); /输出undefined,因为没有赋值
console.log(a);   /输出undefined,此时声明了a,但赋值没有提升上来
var a = 1;  

思路总结

函数声明整体提升(提升到整个逻辑代码的最上面),变量只有声明提升,但是赋值是不提升的
所以我们一直强调 var a = 1的步骤为:1. 声明变量a;  2. 将1赋值给a

3.暗示全局变量 (imply global variable)

 a = 1;
 var b=2console.log(a); // 输出 1

实际上在全局里   写不写var   都会声明  都会存储在window对象里面
所以在全局概念里   a = window.a     b = window.b

function test(){
var a =  1;
b = 1;
}
test();
console.log(window.b); /输出1
console.log(window.a); /输出undefined

在函数内部,没有声明这个变量,而直接给这个变量赋值的话,那它就提升到全局变量里(存到window里)  内部声明了的 (如上述的a) 还是局部变量

4.预编译

一般代码执行过程:

  • 1 通篇检查语法错误
  • 1.5 预编译的过程
  • 2 解释一行执行一行 预编译:函数执行之前要进行的步骤
 function test(a) {
            console.log(a); //输出function a(){} 因为此时a还没有赋值
            var a = 1;
            console.log(a); //输出1
            function a() { }
            console.log(a); //输出1
            var b = function () { }
            console.log(b); //输出 function () { }
            function d() { }
        }
        test(2);
}

预编译时产生AO(activation object 活跃对象,也叫函数上下文 )
上述函数步骤:

  • 1.创建AO的对象,寻找形参和变量声明 AO = {
    a:undefined,
    b:undefined }
  • 2.把实参的数值赋给形参 AO = {
    a:undefined --> 2,
    b:undefined
    }
  • 3.寻找函数声明,给变量赋值函数体 AO = {
    a:undefined --> 2,--> function(){}
    b:undefined
    d: function d(){} }

   预编译执行结束,执行函数: AO = {
a:undefined --> 2,--> function(){} --> 1
b:undefined -> function(){}
d: function d(){} }

  • 例子:
  function test(a,b){
  console.log(a);
  c = 0;
  var c;
  a = 5;
  b = 6;
  console.log(b);
  function b(){}
  function d(){}
  console,log(b);
  }
  test(1);
  //输出1 6 6

最后执行函数时:console.log(a);是第一句,此时不知道a的值,在预编译里面去找,所以 a = 1

console.log(b) 第一个输出6

第二个console.log(b)也是6,因为function b(){}、function d(){}在预编译已经做过了不需要再做。函数执行时,如果之前没有出现var赋值的语句,就会提取预编译里面的函数声明,但是这里之前已经有语句:var b=6;

5. GO

GO:global object 全局上下文
跟AO差不多
1.找变量声明  a : undefined
2.找函数声明 a : undefined 、 function a(){}

最后执行函数:第一句便有了a又赋值1: a : undefined -->function a(){} --> 1

var a = 1;
function a(){
console.log(2);
}
console.log(a); //输出1

其实GO就是window     GO===window   它两没区别
window在存储全局变量时也是这么存的

console.log(a,b); /输出 f a(){} , undefined
function a(){}
var b = function(){}、。。。。。

1.寻找变量:b:undefined
2.找函数声明: a: function a(){} ,因为b是函数表达式,所以不会参与此步骤
3.执行函数 :此时 var b = function(){}在后面 所以不会输出function(){}

例子2:

function test(){
       var a = b = 1;
       console.log(a); //输出1
       console.log(b); //输出1
       }
       test();

1.创立GO
2.AO 找变量声明 AO = {
a: undefined,
}
3.执行函数 看到b了 b没有声明
在GO里面挂着 GO = {
b: 1;
}
4. 执行函数 求a的值 在AO里面去找 找到了a=b--> 去GO里面找 b = 1;故a = 1;
5. 执行函数,求b的值 在AO里面去找 没有--> 去GO里面找 b = 1;

例子3

  var b = 1;
       function test() {
          var a = 1;
          var b = 2;
          console.log(b);//2
          /函数内部自己有,就先找函数内部
      }
      test();

此例中,证明了执行函数时,先找AO,没找到再去找GO

例子4:

var b = 3;
        console.log(a); //大函数
        function a(a){
        console.log(a); //小函数
        var a = 2;
        console.log(a); //2
        function a() {}
            var b = 5;
            console.log(b); //5
        }   
a(1);

1.先执行GO,GO ={
b:undefined
a:function a(){...}
所以第一个console.log(a) 就输出 function a(){...}
执行函数时:没有找到a的值只能去预编译里面找。 }

2.执行AO, AO={ a:undefined; -->1 --> function a(){}
而后面输出2 是因为之前var a=2,后面的function a(){}不看,因为做过了,所以输出2
b:undefined; 执行 b=5;}

例子5:

  function test(){
            console.log(b); 
            if(a){
                var b = 2;
            }
            c = 3;
            console.log(c);
        }
       var a;
        test();
        a = 1;
        console.log(a);
       //输出 undefined  3   1
  1. GO = { a : undefined;
    test : function test(){} }

  2. AO={ b:undefined (b要变量声明,因为此时if语句没有执行,此时不看if,只看有没有变量声明)
    }

  3. c没有var 提升到全局中去:
    GO = { a : undefined;
    test : function test(){}
    c:3
    }

6. 实战

<script>
 function test(){
        return a;
        a = 1;
        function a(){}
        var a = 2
     }
     console.log(test()); //输出function a(){}
</script>

执行时第一句就是return,此时直接返回预编译最后时 a 的值

<script>
   a = 1;
     function test(e) {
         function e() { }
         arguments[0] = 2;
         console.log(e);//2
         if (a) {
             var b = 3;
         }
         var c;
         a = 4;
         var a;
         console.log(b);//undefined
         f = 5;
         console.log(c);//undefined
         console.log(a);//4
     }
     var a;
     test(1);
     //GO: { 
// a:undefined->1 ,
//test:function test(){...}
// }
//AO:{ 
//e:undefined ->function ->1 ->2
//b:undefined (if(a)时,a的值还是为undefined,所以不执行该语句)
//c:undefined
//a:undefined ->4  
//AO中 a有值为undefined 主要是变量声明了 不需要去人家GO里面找
</script>

AO中 a变量声明了 不需要去人家GO里面找
此例中 function test(e) 即形参只有一个,为e