美文网首页
0103函数、作用域链、声明前置、递归

0103函数、作用域链、声明前置、递归

作者: lingfighting | 来源:发表于2017-01-11 13:15 被阅读46次

    1 . 函数声明和函数表达式有什么区别

    函数声明

    function name(param1, param2, ..., paramN){
       statements;
    }
    

    使用function关键字声明一个函数,再指定一个函数名,叫函数声明。此函数能实现声明前置,函数的调用可以在任意位置,即声明前和声明后调用均可。

    函数表达式

    function [name](param1, param2, ..., paramN) { 
    statements;
    }
    

    函数表达式非常类似于函数声明,并且拥有几乎相同的语法。函数表达式与函数声明的最主要区别是函数名称,在函数表达式中可忽略它,从而创建匿名函数的方式来声明一个函数。

    声明前置的是接收函数指针的变量,而不是函数本身,所以必须将声明放在调用前面。

    2 . 什么是声明前置

    浏览器在解析JavaScript代码时,会将所有的变量声明和函数声明提升到它们当前的作用域的最前面。
    全局作用域和函数作用域下分别实现各自的声明前置。
    当发生变量和函数重名时,先前置,后覆盖。

    3 . 求n!,用递归来实现

    function f(n){
      if (n == 1){
        return 1;
      }
      return n * f(n-1);
    }
    

    4 . 什么是立即执行的函数表达式?有什么作用?

    立即执行的函数表达式:使用某种运算方式将函数变成一个表达式,立即得到函数的结果,完成函数调用。

    实现方式:

    • ()包裹函数,得到函数表达式的一个结果---函数名,然后使用函数名调用函数。因为在javascript里,括号内部不能包含语句,当解析器对代码进行解释的时候,先碰到了(),然后碰到function关键字就会自动将()里面的代码识别为函数表达式而不是函数声明
    (function(){
         var a = 1;
    })();
    

    或则

    (function(){
         var a = 1;
    }());
    
    • 使用[]或则或则&&运算符
    // 在数组初始化器内只能是表达式
    [function fn2() {}]; 
    // 逗号也只能操作表达式
    1, function fn3() {};
    //` && `两边也是表达式
    true && function () { /* code */ } ();
    
    • 使用一元运算符得到立即执行函数表达式
    !function () { /* code */ } ();
    ~function () { /* code */ } ();
    -function () { /* code */ } ();
    +function () { /* code */ } ();
    

    作用:利用函数作用域下,变量用完即释放的功能,来实现隔离作用域,污染防止全局变量的效果。

    5 . 如下代码输出什么? 写出作用域链查找过程伪代码

    var x = 10;
    bar();
    function foo() { 
    console.log(x);
    }
    function bar(){
     var x = 30;
     foo(); // 输出什么
    }
    

    foo(); // 输出10
    作用域链查找过程伪代码:

    globalContext = {
      AO:{
        x: 10,
        foo: function,
        bar: function,
      },
      Scope: null,
    }
    //在当前的执行上下文内声明的函数,这个函数的[[scope]]就是当前执行上下文
    //调用函数的时候进入到函数的执行上下文
    fooContext.Scope = globalContext;
    barContext.Scope = globalContext;
    
    fooContext = {
      AO:{
      },
      Scope: globalContext,
    }
    
    barContext = {
      AO:{
        x: 30,
      },
      Scope: globalContext,
    }
    
    

    6 . 如下代码输出什么? 写出作用域链查找过程伪代码

    var x = 10;
    bar() // 输出什么
    function bar(){ 
      var x = 30;
      function foo(){
        console.log(x) 
      } 
      foo();
    }
    

    bar() // 输出30
    作用域链查找过程伪代码:

    globalContext = {
      AO:{
        x: 10,
        bar: function,
      },
      Scope: null,
    }
    barContext.Scope = globalContext;
    
    barContext = {
      AO:{
        x: 30,
        foo: function,
      },
      Scope: globalContext,
    }
    fooContext.Scope = barContext;
    
    fooContext = {
      AO:{
      },
      Scope: barContext,
    }
    

    7 . 一下代码输出什么? 写出作用域链的查找过程伪代码

    var x = 10;
    bar() // 输出什么
    function bar(){
      var x = 30; 
      (function (){ console.log(x) })();
    }
    

    bar() // 输出30
    作用域链查找过程伪代码:

    globalContext = {
      AO:{
        x: 10,
        bar: function,
      },
      Scope: null,
    }
    barContext.Scope = globalContext;
    
    barContext = {
      AO:{
        x: 30,
        (function(){}): funtion,
      },
      Scope: globalContext,
    }
    (function(){}).Scope = barContext;
    
    (function(){})Context = {
      AO:{
      },
      Scope: barContext,
    }
    

    8.以下代码输出什么? 写出作用域链查找过程伪代码

    var a = 1;
    function fn(){ 
      console.log(a); 
      var a = 5; 
      console.log(a); 
      a++; 
      var a;
      fn3(); 
      fn2(); 
      console.log(a); 
      function fn2(){ 
        console.log(a); 
        a = 20; 
      }
    }
    
    function fn3(){ 
      console.log(a);
      a = 200;
    }
    fn();
    console.log(a); 
    

    输出:undefined 5 1 6 20 200
    作用域链查找过程伪代码:

    1.
    globalContext = {
      AO:{
        a: 1,
        fn: function,
        fn3: function,
      },
      Scope: null,
    }
    fnContext.Scope = globalContext;
    fn3Context.Scope = globalContext;
    
    fnContext = {
      AO:{
        a: undefined,//fn第一个console.log(a)
        fn2: funtion,
      },
      Scope: globalContext.AO,
    }
    fn2Context.Scope = fnContext;
    
    fn2Context = {
      AO:{
      },
      Scope: fnContext,
    }
    
    fn3Context = {
      AO:{
      },
      Scope: globalContext,
    }
    
    2. 
    fnContext = {
      AO:{
        a: 5,//fn第二个console.log(a)
        fn2: funtion,
      },
      Scope: globalContext,
    }
    
    3. 
    globalContext = {
      AO:{
        a: 1,//fn3的console.log(a)
        fn: function,
        fn3: function,
      },
      Scope: null,
    }
    fnContext = {
      AO:{
        a: 6,//a++之后
        fn2: funtion,
      },
      Scope: globalContext,
    }
    
    fn3Context = {
      AO:{
      },
      Scope: globalContext,
    }
    
    4.
    globalContext = {
      AO:{
        a: 200,//fn3的a = 200
        fn: function,
        fn3: function,
      },
      Scope: null,
    }
    fnContext = {
      AO:{
        a: 6,//fn2的console.log(a)
        fn2: funtion,
      },
      Scope: globalContext,
    }
    
    fn2Context = {
      AO:{
      },
      Scope: fnContext,
    }
    
    fn3Context = {
      AO:{
      },
      Scope: globalContext,
    }
    
    5.
    fnContext = {
      AO:{
        a: 20,//fn2里a = 20;fn的第三个console.log(a)
        fn2: funtion,
      },
      Scope: globalContext,
    }
    
    6.
    globalContext = {
      AO:{
        a: 200,//全局最后的console.log(a)
        fn: function,
        fn3: function,
      },
      Scope: null,
    }
    

    9.以下代码输出什么?画出执行过程作用域伪代码(难度五颗星,用兴趣的同学可选做)

    function fn(){ 
      var x = 1; 
      function fn2(){
        x++;
       console.log(x) ; 
      } 
      return fn2;
    }
    var foo = fn();
    var bar = fn();
    foo();
    bar();
    foo();
    

    输出:2 2 3
    作用域链查找过程伪代码:

    globalContext = {
      AO:{
        fn: function,
        foo: function,//fn2
        bar: function,//fn2
      },
      Scope: null,
    }
    fnContext.Scope = globalContext;
    fooContext.Scope = globalContext;
    barContext.Scope = globalContext;
    
    fnContext = {
      AO: {
        x: 1,
        fn2: function,
      }
      Scope: globalContext;
    }
    fn2Context.Scope = fnContext;
    
    fn2Context = {
      AO: {
      }
      Scope: fnContext;
    }
    
    //首先,foo和bar是两个不同的变量,占用不同的内存资源,是两个独立的实例,互不影响。
    
    1.foo();
    
    fooContext = {
      AO: {
      }
     //foo的Scope具有globalContext和fnContext双重属性
      Scope: fnContext, 
             globalContext,
    }
    
    fnContext = {
      AO: {
        x: 2,//x++后
        fn2: function,
      }
      Scope: globalContext;
    }
    
    2.bar();
    
    barContext = {
      AO: {
      }
      //bar的Scope具有globalContext和fnContext双重属性,且和foo的Scope互不影响
      Scope: fnContext, 
             globalContext,
    }
    
    fnContext = {
      AO: {
        x: 2,//x++后
        fn2: function,
      }
      Scope: globalContext,
    }
    
    3.foo();
    
    fooContext = {
      AO: {
      }
      //foo的Scope具有globalContext和fnContext双重属性
      Scope: fnContext, 
             globalContext,
    }
    
    fnContext = {
      AO: {
        x: 3,//x++后
        fn2: function,
      }
      Scope: globalContext,
    }
    

    相关文章

      网友评论

          本文标题:0103函数、作用域链、声明前置、递归

          本文链接:https://www.haomeiwen.com/subject/zutzvttx.html