js函数

一、函数声明和函数表达式有什么区别?

  • 函数声明和函数表达式的区别:

    • 函数声明可以提升到其他代码之前(即函数声明前置),但函数表达式不能提升到其他代码之前
    • 函数声明必须给定函数名称,函数表达式则可以忽略函数名称
    • 函数表达式后面有分号,函数声明没有
  • 函数声明:

    getsum(1, 2);    //3
    function getsum(num1, num2){
        return num1+num2;
    }
    

等价于

  function getsum(num1, num2){
      return num1+num2;
  }
  getsum(1, 2);    //3
  • 函数表达式:

    getsum(1, 2);    //Uncaught TypeError: getsum is not a function
    var getsum = function(num1, num2){
        return num1+num2;
    };
    

等价于

  var getsum;
  getsum(1, 2);    ////Uncaught TypeError: getsum is not a function
  getsum = function(num1, num2){
      return num1+num2;
  };

二、什么是变量声明前置?什么是函数声明前置?

  • 变量声明前置就是把变量的声明提升到当前作用域的最前面。如下例:

    console.log(a);  //undefined
    var a = 1;
    

    等价于

    var a;
    console.log(a);  //undefined
    a = 1;
    

下面这个例子也是输出undefined,因为输出的是main()内的局部变量
var a = 1;
function main(){
console.log(a);
var a = 2;
}
main(); //undefined
等价于

  var a;
  function main(){
      var a;
      console.log(a);
      a = 2;
  }
  a = 1;
  main();    //undefined
  • 函数声明前置就是把函数声明提升到当前的最前面(位于变量声明前置后面)

    var num1 = 1, num2 = 2;
    getsum(num1, num2);    //3
    function getsum(num1, num2){
        return num1 + num2;
    } 
    

等价于

  var num1, num2;
  function getsum(num1, num2){
      return num1 + num2;
  }
  num1 = 1;
  num2 = 2;
  getsum(num1, num2);    //3

三、arguments是什么?

arguments是一个用于存放函数所有传入参数的类数组对象。

  function main(a, b, c){
      return arguments;
  }
  main(1, 2, 3);      //[1, 2, 3]

arguments的值由函数的传入参数决定,与函数定义的参数无关

四、函数的重载怎样实现?

  • 函数的重载是指为一个函数编写多个定义,只要这两个定义的签名(接受的参数的类型和数量)不同即可。也就是定义几个名字相同的函数但参数的类型和数量不同,当函数接受到不同的参数时就按照不同的定义执行。

  • ECMAScript函数没有签名,所以ECMAScript函数不能重载,如果同时定义两个名称相同的函数,后定义的那个函数会覆盖先定义的函数

    function addnum(num1, num2){
        return num1+num2;
    }
    function addnum(num1, num2, num3){
        return num1+num2+num3;
    }
    console.log(addnum(1, 2)) ;   //NaN, 后定义的函数覆盖了先定义的函数
    console.log(addnum(1, 2, 3)) ;    //6
    
  • 可以通过arguments来实现函数重载的功能。如下:

    function addnum(num){
        var sum = 0;
        for(var i = 0; i < arguments.length; i++){
            sum += arguments[i];
        }
        return sum;
    }
    console.log(addnum(1));    //1
    console.log(addnum(1, 2));    //3
    

五、立即执行函数表达式是什么?有什么作用

  • 立即执行函数表达式(IIFE——Immediately Invoked Function Expression),是将函数的定义放在一个圆括号里,让JavaScript引擎将其理解为一个表达式,再在函数的定义后面加一个(),以达到定义函数后立即调用该函数的效果。下面两种形式在功能上是一致的:

    (function(){ /* code */ }());    //立即执行函数表达式
    (function(){ /* code */ })();    //立即执行函数表达式
    
  • 立即执行函数表达式的作用

    • 可以创建匿名函数,避免污染全局变量

    • 形成一个单独的作用域,可以封装一些外部无法读取的私有变量

      // 写法一
      var tmp = newData;
      processData(tmp);
      storeData(tmp);
      
      // 写法二
      (function (){
          var tmp = newData;
          processData(tmp);
          storeData(tmp);
      }());
      

上面代码中,写法二比写法一更好,因为完全避免了污染全局变量

六、什么是函数的作用域链

  • 作用域
    作用域就是变量和函数的可访问范围,控制着变量与函数的可见性和生命周期。在Javascript中变量的作用域有全局作用域和局部作用域。

    • 全局作用域
      变量没有在函数内声明或者声明的时候没有带var就是全局变量,拥有全局作用域,window对象的所有属性拥有全局作用域,在代码任何地方都可以访问。
    • 局部作用域
      函数内部声明并且以var修饰的变量就是局部变量,只能在函数体内使用,函数的参数虽然没有使用var但仍然是局部变量。
  • 执行环境(运行上下文)
    执行环境(execution context)定义了变量或函数有权访问的其他数据,决定了他们的各自行为。每个执行环境都有一个与之关联的变量对象(variable object,VO),执行环境中定义的所有变量和函数都会保存在这个对象中,解析器在处理数据的时候就会访问这个内部对象。
    全局执行环境是最外层的一个执行环境,在web浏览器中全局执行环境是window对象,因此所有全局变量和函数都是作为window对象的属性和方法创建的。每个函数都有自己的执行环境,当执行流进入一个函数的时候,函数的环境会被推入一个函数栈中,而在函数执行完毕后执行环境出栈并销毁,保存在其中的所有变量和函数定义随之销毁,控制权返回到之前的执行环境中,全局的执行环境在应用程序退出(浏览器关闭)才会被销毁。

  • 作用域链
    当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象(activation object)作为变量对象。活动对象在最开始时只包含一个变量,即arguments对象(这个对象在全局环境中是不存在的)。作用域链中的下一个变量对象来自包含(外部)环境,而再下一个变量对象则来自下一个包含环境。这样,一直延续到全局执行环境;全局执行环境的变量对象始终都是作用域链中的最后一个对象。

    标识符解析是沿着作用域链一级一级地搜索标识符的过程。搜索过程始终从作用域的前端开始,然后逐级地向后回溯,直至找到标识符为止(如果找不到标识符,通常会导致错误发生)

代码

1.以下代码输出什么?

    function getInfo(name, age, sex){
        console.log('name:', name);
        console.log('age:', age);
        console.log('sex:', sex);
        console.log(arguments);
        arguments[0] = 'valley';
        console.log('name:', name);
    }
    getInfo('hunger', 28, '男');  
    //name: hunger 
    //age: 28 
    //sex: 男
    //["hunger",28,"男"] 
    //name: valley
    getInfo('hunger', 28);  
    //name: hunger 
    //age: 28 
    //sex: undefined 
    //["hunger",28] 
    //name: valley
    getInfo('男');  
    //name: 男 
    //age: undefined 
    //sex: undefined 
    //["男"] 
    //name: valley

2.写一个函数,返回参数的平方和

    function sumOfSquares(){}
    sumOfSquares(2,3,4);
    sumOfSquares(1,3);

    function sumOfSquares(num1, num2){
        var sum = 0;
        for(var i = 0; i < arguments.length; i++){
            var a = arguments[i];
            sum += a*a;
        }
        return sum;
    }
    console.log(sumOfSquares(2,3,4)); // 29
    console.log(sumOfSquares(1,3));  // 10

3.如下代码的输出?为什么

    console.log(a);  // undefined,变量声明提升
    var a = 1;
    console.log(b);  // 报错,因为变量b没有声明

等价于

    var a;
    console.log(a);  // undefined
    a = 1;
    console.log(b);  // 报错,因为变量b没有声明

4.如下代码的输出?为什么

    sayName('world');  // hello world
    sayAge(10);  // 报错,因为函数表达式不会前置,执行到这里时sayAge没有指向任何函数
    function sayName(name){
        console.log('hello', name);
    }
    var sayAge = function(age){
        console.log(age);
    }

等价于

    var sayAge;
    function sayName(name){
        console.log('hello', name);
    }
    sayName('world');  // hello world
    sayAge(10);  // 报错,执行到这里时sayAge没有指向任何函数
    sayAge = function(age){
        console.log(age);
    }

5.如下代码的输出?为什么

    function fn(){}
    var fn = 3;
    console.log(fn);  // 3

等价于

    var fn;
    function fn(){}
    fn = 3;
    console.log(fn);  // 3

6.如下代码的输出?为什么

    function fn(fn2){
        console.log(fn2);
        var fn2 = 3;
        console.log(fn2);
        console.log(fn);
        function fn2(){
            console.log('fnnn2');
        }
    }
    fn(10);
    // function
    // 3
   // function

等价于

    function fn(fn2){
        var fn2;
        function fn2(){
            console.log('fnnn2');
        }
        console.log(fn2);  
        fn2 = 3;
        console.log(fn2);  
        console.log(fn);  
    }
    fn(10);
    // function 
    // 3
   // function

7.如下代码输出什么?为什么

    var fn = 1;
    function fn(fn){
        console.log(fn);
    }
    console.log(fn(fn));  // 报错,这里变量fn存放的是一个数值,没有指向函数

等价于

    var fn
    function fn(fn){
        console.log(fn);
    }
    fn = 1;
    console.log(fn(fn));  // 报错,这里变量fn存放的是一个数值,没有指向函数

8.如下代码的输出?为什么

    console.log(j);  // undefined
    console.log(i);  // undefined
    for(var i=0; i<10; i++){
        var j = 100;
    }
    console.log(i);  // 10
    console.log(j);  // 100

等价于

    var i;
    var j;
    console.log(j);  // undefined
    console.log(i);  // undefined
    for(i=0; i<10; i++){
        j = 100;
    }
    console.log(i);  // 10
    console.log(j);  // 100

变量i,j都是全局变量,只有在函数内才会存在局部变量

9.如下代码的输出?为什么

    fn();
    var i = 10;
    var fn = 20;
    console.log(i);
    function fn(){
        console.log(i);
        var i = 99;
        fn2();
        console.log(i);
        function fn2(){
            i = 100;
        }
    }

等价于

    var i;
    var fn;
    function fn(){
        var i;
        function fn2(){
            i = 100;
        }
        console.log(i);
        i = 99;
        fn2();
        console.log(i);
    }
    fn(); 
    /**
     * console.log(i);  // undefined 
     * fn2();  // 没有输出
     * console.log(i);  // 100
     */
    i = 10;
    fn = 20;
    console.log(i);  // 10

10.如下代码的输出?为什么

    var say = 0;
    (function say(n){
        console.log(n);
        if(n<3) return;
        say(n-1);
    }(10));
    /**
     *立即执行函数表达式,传入参数为10,即n=10
     *console.log(n);  // 10
     *if(n<3) return;  //n<3时跳出循环
     *say(n-1);  // 9 8 7 6 5 4 3 2
     */
    console.log(say);  // 0, 这里的say是全局变量say,立即执行函数表达式中的say是局部变量

本文版权属吴天乔所有,转载务必注明出处。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容

  • 函数声明和函数表达式有什么区别 (*)解析器会率先读取函数声明,并使其在执行任何代码之前可以访问;函数表达式则必须...
    coolheadedY阅读 385评论 0 1
  • 1. 函数声明和函数表达式有什么区别 (*) 函数在JS中有三种方式来定义:函数声明(function decla...
    进击的阿群阅读 440评论 0 1
  • 概念 1、函数声明和函数表达式有什么区别? ECMAScript规定了三种声明函数方式: 构造函数首先函数也是对象...
    周花花啊阅读 465评论 1 1
  • 定义: JavaScript函数是指一个特定的代码块,可能包含多条语句,可以通过名字来供其他语句调用以执行函数包含...
    饥人谷_sunny阅读 314评论 0 0
  • 一、函数的作用域 首先,作用域就是指变量的作用范围然后,在JS中只有两个作用域:1.全局作用域,2.局部作用域(函...
    大春春阅读 525评论 0 6