js函数相关基础知识问答

一、问答

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

函数声明表示方法的例子:

function printName(){
 alert("shengming");
}
printName();

函数表达式的例子:

var printName=function(){
alert("biaodashi");
}

那么他们之间有什么区别呢?看下面的例子

console.log( shengMing );
console.log( biaodashi );
function shengMing(){
 alert("shengming")
};
var biaodashi=function biaoDaShi(){
 alert("biaodashi")
};
console.log( shengMing );
console.log( biaodashi );

运行后:

Paste_Image.png

由以上可以看出,即使声明函数shengMing()是在后面声明的,但在前面也可调用(第一个console.log( shengMing );能够正常运行),但是表达函数则不行(第一个console.log( biaodashi ); 运行结果显示undefined);对于函数声明语句,函数名称和函数体均提前声明了,可以在声明之前调用它;但对于函数表达式,只有函数变量声明提前了,但是函数的初始化代码仍然在原来的位置;

(二)什么是变量的声明前置?什么是函数的声明前置?
  • 变量的声明前置,是指即使我们没有在使用变量前先声明这个变量,但是由于变量提升(即变量声明的前置)的存在,我们可以在声明前使用该变量,只不过这个变量的默认值是undefined,但解析器不会报错;例如:
Paste_Image.png
  • 同理,对于函数也存在函数的声明前置的情况,其实第一题就说明了这一点,下面再举个例子:
Paste_Image.png

当然对于表达式函数也适用,例如下面的例子:

Paste_Image.png
(三)arguments 是什么 ?

arguments 是一个类数组对象。代表传给一个function的参数列表。
可以在函数内部通过使用 arguments 对象来获取函数的所有参数。这个对象为传递给函数的每个参数建立一个条目,条目的索引号从 0 开始。arguments 对象并不是一个真正的Array。它类似于数组,但没有数组所特有的属性和方法,除了 length。例如,它没有 pop 方法。不过可以将其转换成数组。另外:arguments 对象仅在函数内部有效,在函数外部调用 arguments 对象会出现一个错误。如果你调用一个函数,当这个函数的参数数量比它显式声明的参数数量更多的时候,你就可以使用 arguments 对象。这个技术对于参数数量是一个可变量的函数来说比较有用。 你可以用 arguments.length 来得到参数的数量,然后可以用 arguments object 来对每个参数进行处理。 (想要得到当一个函数定义时的该函数的参数数量, 请使用 Function.length 属性。)

arguments的属性如下:
arguments.callee
指向当前执行的函数。
arguments.caller
指向调用当前函数的函数。
arguments.length
指向传递给当前函数的参数数量。

  • 下面举个使用arguments的例子:
Paste_Image.png

在声明上述函数时未使用参数,即其不包含命名的参数,这说明在函数中命名的参数只提供便利,但不是必须的。

  • 下面再举个使用arguments.length的例子:
Paste_Image.png
(四)函数的重载怎样实现 ?

由于js不能像传统意义上那样实现重载,因此我们可以通过使用arguments的方法实现非完美的重载;

如下面的例子:

Paste_Image.png
(五)立即执行函数表达式是什么?有什么作用 ?

类似于

Paste_Image.png

类似于上述函数的写法叫做「立即执行函数」也叫「自执行匿名函数」(self-executing anonymous function);「立即执行函数表达式」(Immediately-Invoked Function Expression,简称IIFE);
其中一般推荐使用第一种写法,但是目前很多比较好的js library 使用的都是第二种方式。 比如: web 图形绘制的: git , draw2d ,....

(六)什么是函数的作用域链?

函数对象和其他对象一样,拥有可以通过代码访问的属性和一系列供js引擎访问的内部属性,其中一个内部属性是[scope],该属性包括了函数被创建的作用域中的对象集合,这个集合称为函数的作用域链,它决定了哪些能够被函数访问;

举个例子:

Paste_Image.png

二、代码

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, '男');
    getInfo('hunger', 28);
    getInfo('男');

运行结果会如下:

    /*  getInfo('hunger', 28, '男')运行结果:

        name:hunger
        age:28
        sxe:男
        {valley, 28, 男}
        name valley
 
    */


    /*   getInfo('hunger', 28)运行结果:

        name:hunger
        age:28
        sxe:undefind
        {valley,28}
        name valley


    */

    /*   getInfo('男')运行结果:

        name:男
        age:undefind
        sxe:undefind
        {valley}
        name valley


    */
Paste_Image.png
2.写一个函数,返回参数的平方和?如
   function sumOfSquares(){
   }
   sumOfSquares(2,3,4);   // 29
   sumOfSquares(1,3);   // 10
function sumOfSquares(){
        for (var i = 0,x = 0; i < arguments.length; i++) {
            x=x+arguments[i]*arguments[i];          
         }
        console.log(x);
    }
Paste_Image.png
3.如下代码的输出?为什么 ?
    console.log(a);
    var a = 1;
    console.log(b);

上述代码相当于:

    var a;
    console.log(a);
    a = 1;
    console.log(b);

输出为 undefined;b is not defined; 由于变量提升的存在,导致console.log(a)时,不会出现a is not defined,但是由于console.log(a)之前a未赋值,所以才会导致出现 undefined; 而对于console.log(b)语句,由于b既未声明也未赋值,所以才会报错b is not defined错误;

Paste_Image.png
4.如下代码的输出?为什么 ?
    sayName('world'); //hello world (解释:该函数为声明函数,存在提前声明的情况;)
    sayAge(10);/*sayAge is not a function (解释:该函数为表达式函数,
不存在提前声明的情况,所以会报错)*/
    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');
    sayAge(10);// sayAge is not a function 
 sayAge = function(age){
        console.log(age);
    };
Paste_Image.png
5.如下代码的输出?为什么 ?
    function fn(){}
    var fn = 3;
    console.log(fn);//3

上述代码相当于:

     var fn; //fn 此时为普通变量
    function fn(){}    //fn此时为函数名
    fn = 3;  /*fn此时值等于3,因为在同一个作用域内定义了名字相同的变量和方法的话,无论其顺序如
何,变量的赋值会覆盖方法的赋值;*/
    console.log(fn); //打印时输出3
Paste_Image.png
6.如下代码的输出?为什么 ?
    function fn(fn2){
       console.log(fn2);
       var fn2 = 3;
       console.log(fn2);
       console.log(fn);
       function fn2(){
            console.log('fnnn2');
        }
     }
    fn(10);

上述代码相当于:

    function fn(fn2){
       var fn2;
       function fn2(){
            console.log('fnnn2');
        }
       console.log(fn2);   //
/* 由于同个作用域下,变量声明和函数声明存在命名冲突时,变量声明前置要比函数声明前置的优先级底,因此此时打印出的是函数*/
       fn2 = 3;
       console.log(fn2); //3   
   /*此时fn2被赋值3了,因为在同一个作用域中,定义了同一个名字的变量
和方法时,无论顺序如何,变量的赋值会覆盖方法的赋值*/
       console.log(fn); //  此时会打印函数fn本身 

     }
    fn(10);

因此结果为

Paste_Image.png

如果将此题改成下面的代码,结果将是怎样的呢?

    function fn(fn2){
       var fn2=200;
       function fn2(){
            console.log('fnnn2');
        }

       console.log(fn2);
       var fn2 = 3;
       console.log(fn2);

     }
    fn(10);

其实上面的代码相当于

    function fn(fn2){
       var fn2=200;
       function fn2(){
            console.log('fnnn2');
        }

       console.log(fn2); //200 此时并没有输出函数fn2,为什么呢?
/*因为同一个作用域中,定义了名字相同的变量和方法的话,无论顺序如何
变量的赋值会覆盖方法的赋值;
*/
       var fn2 = 3;
       console.log(fn2); //3

     }
    fn(10);

输出结果:

Paste_Image.png

如果再将代码改成:

    function fn(fn2){
        var fn2=200;
       function fn2(){
            console.log('fnnn2');
        }

       console.log(fn2);
        fn2 = 3;
       console.log(fn2);

     }
    fn(10);
    console.log(fn2); //此处会报错,因为由于函数作用域的存在,此处的fn2并未定义变量且赋值;

则结果为

Paste_Image.png
7.如下代码的输出?为什么?
    var fn = 1;
    function fn(fn){
         console.log(fn); 
    }
    console.log(fn(fn)); 

上述代码相对于

    var fn ;
    
    function fn(fn){
         console.log(fn); 
    };
    fn = 1;
    console.log(fn(fn)); //报错 fn  is not a function
/* 由于同一个作用域中,定义同一个名字的变量和方法时,变量赋值会覆盖方法的赋值,因此此时解析器
并不能够识别fn为函数,但是在打印时又以函数的方式打印,因此会报错*/

其实上面的例子可简化成这样的理解

Paste_Image.png

打印a(a) ,解析器会把它当作成要打印一个函数,但是a并不是一个函数,因此会报错。

8.如下代码的输出?为什么 ?
    //作用域
    console.log(j); 
    console.log(i); 
    for(var i=0; i<10; i++){
        var j = 100;
    }
    console.log(i); 
    console.log(j); 

其实上面的代码相当于

   var j ;
   var i ;
    console.log(j);  // undefined 
/*解释:由于变量提升的存在,导致此处提示j未被赋值,但不抱错*/
    console.log(i); //undefined 
/*解释:同理,由于变量提升的存在,
导致此处提示i未被赋值,但不抱错*/
    for(var i=0; i<10; i++){
        var j = 100;
    }
    console.log(i); //10 (解释:for语句执行完后,i值为10)
    console.log(j); // 100 (解释:for语句执行完后,j值为100)
Paste_Image.png
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);  //undefinded
/*此时i并未被赋值,因此为undefinded*/
        var i = 99;
        fn2(); //执行后i为100;
        console.log(i);  //100
/*此时打印i,i的值为100*/

    }

    fn();
    var i = 10;
    var fn = 20;
    console.log(i); //10 
/*虽然i在function内部为100但由于函数作用域的存在及i的外部赋值,在外部的为10;*/

Paste_Image.png
10.如下代码的输出?为什么?
    var say = 0;
    (function say(n){ 
        console.log(n);

        if(n<3) return; 
        say(n-1);
    }( 10 )); //输出 10,9,8,7,6,5,4,3,2
/*该函数为立即执行函数,因此会马上执行,当n为2时,因为2<3,因此会立即跳出该函数*/
    console.log(say); //输出0  
/*因为在该作用域中,变量say已经被赋值了0,在同一个作用域中,变量和方法同名时,无论顺序如何,
变量的赋值会覆盖方法的赋值,更何况say()为立即执行函数;
*/
Paste_Image.png

如果将题中代码改成

    var say = 0;
    var n=10086;
    function say(n){ 
        console.log(n); 
        if(n<3) return; 
        say(n-1);
    };
    console.log(say(n)); 
    console.log(say(n));   /*此时解析器以为要执行say(n)函数,但由于同一个作用域下,若存在同
名的变量和方法,变量的赋值会覆盖方法的赋值,因此say还是被看成值为0的变量,而say(n)又不是一个函
数,因此会报错说say不是一个函数
*/

上述代码执行后将会报错。

Paste_Image.png

补充:作用域链相关资料

**本文版权归本人即简书笔名:该账户已被查封 所有,如需转载请注明出处。谢谢! *

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

推荐阅读更多精彩内容