日夜谈——函数和作用域

函数和作用域

<h4>1.函数声明和函数表达式有什么区别 (*)</h4>
区别:
<li>函数声明后面的分号可加可不加,不加也不影响接下来语句的执行,但是函数表达式后没有分号结束,JS引擎会自动默认后面的语句也是函数表达式的一部分。
<li>变量提升,函数声明会将整个函数代码块提升至作用域最顶部,而函数表达式只提升变量。

function foo() {} //函数声明

var foo = function() {} //函数表达式

例如:
提升变量 var foo
var foo = function() {};

提升函数function foo() {}
function foo() {};

参考资料:<a href="https://libuchao.com/2012/06/25/function-declaration-vs-function-expression">函数声明与函数表达式</a>
</br>
<h4>2.什么是变量的声明前置?什么是函数的声明前置</h4>
变量的声明前置:JavaScript在解析代码时,会存在变量提升的工作机制,其流程是JS解析器会在解析阶段,会将所有被声明的变量提升至作用域的最顶部,然后在解析剩余的代码。

函数的声明前置:声明前置这一机制同样也适用于函数,只不过作用在函数的时候,是将整个函数代码块提升前置。

</br>
<h4>3.arguments 是什么</h4>
arguments是一个类数组对象。而argument包含了函数运行时所有的参数,可以在函数内部通过使用arguments来获取函数的所有参数,这个对象为传递给函数的每个参数建立一个条目,条目的索引号从 0 开始。另外arguments只能在函数体内部使用。
<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/arguments">详细MDN文档</a>
</br>
<h4>4.函数的重载怎样实现</h4>
<li><b>啥是函数重载?</b></li>
允许在同一范围中声明几个功能类似的同名函数,但是这些同名函数的形式参数必须不同,这就是重载函数。
<li><b>函数重载的作用?</b></li>
函数重载的主要作用是用来实现功能类似而所处理的数据类型不同的问题。
<li><b>JavaScript函数重载实现</b></li>
其实是<b>“利用arguments模拟函数重载”</b>用arguments对象获取到该函数的所有传入参数实现重载。

function sum(){
         var sum = 0;
         for(var i =0;i<arguments.length;i++){
         sum+=arguments[i]
}
         return sum;
}
console.log( sum(1,2) );
console.log( sum(4,5,6) );
console.log( sum(1,2,"HelloWorld") );

</br>
<h4>5.立即执行函数表达式是什么?有什么作用 ?</h4>
<b>什么是立即执行函数</b>
一种声明之后就立即进行该函数执行操作的函数
<b>表达式</b>

写法一:
(function sum(i){
console.log(i)
}());
写法二:
!function sum(i){
console.log(i)
}();

<b>有什么作用?</b>
它的目的有两个:
一是不必为函数命名,避免了污染全局变量;
二是IIFE内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量上面代码中。
<a href="http://javascript.ruanyifeng.com/grammar/function.html#toc24">阮一峰JavaScript标准参考教程</a>
</br>
<h4>6.什么是函数的作用域链</h4>
作用域是指变量存在的范围,可分为全局作用域和局部作用域,变量则开分为全局变量和局部变量。
<li>全局作用域:变量作用范围是全局,直到js运行失效
<li>局部作用域:JS代码块执行完后就失效
<li>作用域链:JavaScript语言特有的”链式作用域”结构(chain scope),子对象在找不到相关变量时,会一级一级地向上寻找所有父对象的变量。

var a = 1;
function foo(){
var b = 2;
c=6;
console.log(a+b)
}
b//b is not not defined
//a是全局变量,只要js运行都会生效;
//b是局部变量,只在函数内部生效
//如果函数内部的变量不加声明,会被当做全局变量。

</br>
<h4>代码</h4>

1.一下代码输出是什么?

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

输出结果:

getInfo('hunger', 28, '男');
name:hunger
age:28
sex:男
["hunger",28,"男"]
name:valley
["hunger", 28, "男"]
name: hunger
age:28
sex:undefined
["hunger",28]
name:valley
getInfo('男')
name:男
age:undefined
sex:undefined
["男"]
name:valley

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

code 2.png
function sumOfSquares(){
    var sum = 0;
    for(var i = 0;i<arguments.length;i++){
        if(typeof arguments[i] !== "number"){
            console.log(arguments[i]+" "+"is not a number!")
        }else{
        sum+=Math.pow(arguments[i],2)
    }
    console.log(sum);
}
sumOfSquares(2,3,4);   //29
sumOfSquares(1,3);    //10

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

  console.log(a);
    var a = 1;
    console.log(b);
结果:
  undefined;
ReferenceError:b is not defined;
因为:JS存在变量提升机制,因此var=a会被提升至作用域最顶部,留下a=1在原来的位置,
因此console.log(a)会输出undefined,而b没有进行变量声明,因此console.log(b)
会出现ReferenceError:b is not defined。

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

    sayName('world');
    sayAge(10); //报错,sayAge is not a function
    function sayName(name){
        console.log('hello ', name);//hello world;
    }
    var sayAge = function(age){
        console.log(age);报错,sayAge is not a function
    };
因为:
sayName函数声明,跟变量声明提前一样,也会进行函数声明前置。
所以sayName的函数打印结果为hello world,sayAge是函数表达式,
不会进行声明提前,所以当调用表达式在函数表达式前面会报错提示sayAge is not a function 
,如果调试表达式在函数表达式后面。就能正常使用。

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

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

输出结果为3
分析:
由于JS具有变量提升机制,因此代码可以变形成:
var fn
function fn(){}
fn=3;
console.log(fn);//3
因:首先var fn提前到了最顶上,然后将其变为一个函数function fn,
之后又将数值3赋值给fn,顶替了函数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 fn2(){
      console.log('fnnn2');
}
3
function fn(fn2){
       console.log(fn2);
       var fn2 = 3;
       console.log(fn2);
       console.log(fn);
       function fn2(){
            console.log('fnnn2');
        }
     }
那么为啥这个样子呢?
我们不妨按照JS的解析顺序来调整代码的位置
function fn(fn2){
        var fn2  //首先局部变量fn2通过变量声明提升函数的最顶部
        function fn2(){
        console.log("fnnn2")
}  //局部变量fn2函数通过函数声明提升上来,因此fn2变为一个函数
        console.log(fn2);  //因此console.log(fn2)输出的是fn2是一个函数,因此输出整个函数。
        fn2=3;  //把数值3赋值给fn2,帮函数fn2顶替
        console.log(fn2);  //因此console.log(fn2)输出的是3
        console.log(fn);  //console.log(fn),首先会在局部作用域fn函数内部需找参数fn,如果找不到,
会从局部作用域提升至全局作用域寻找,然后找到fn函数,因此输出整个函数。
}
   fn(10);  //函数fn()的参数已在自身局部变量中找到,所以该条代码无效;

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

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

输出结果:
fn is not a function
因为:
fn由于函数声明,因此提升至fn=1前面,所有1代替函数成为fn的值,
因此输出console.log(fn(fn))时会报错“fn is not a function”

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

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


输出结果:
    undefined;
    undefined;
    10
    100
分析(由于JS具有变量提升机制,因此我们将代码调整顺序)
    var i
    var j
    console.log(j);
    console.log(i)
    for(i = 0;i<10;i++){
        j = 100;
    }
    console.log(i);
    console.log(j);
分析:
1:由于变量提升机制var i,var j提升至作用域顶部。
2:因此console.log(j),console.log(i)的输出均为undefined。
3:i在for循环中循环10次退出循环,因此i=10,而后面j=100;
4:因为i和j分别得到赋值10和100,因此console.log(j),console.log(i)的输出均为10和100.

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;
        }
    }

输出结果:
undefined
100
10
分析:执行变量提升机制之后,代码变为:
    var i ; //变量提升机制,变量i 和 fn提升至作用域最顶部,但是此时未赋值
    var fn ;
    function fn(){  //fn成为一个函数,并且变量声明前置
        var i;    //fn函数内部声明了var i,未赋值
        function fn2(){  //函数声明前置
            i = 100;  //函数fn2内部为 i 赋值100
        }
        console.log(i); //输出i的值,此时的局部变量i被声明但是未被赋值,所以输出的是undefined;
        i = 99; //i赋值99
        fn2(); //执行函数fn2(),i被赋值100覆盖99
        console.log(i); //因为i=100,因此输出100
    }
    fn(); //执行函数fn();得到的两个值就是undefined和100;
    i = 10;
    fn = 20;//在全局域中为i和j赋值为10和20;
    console.log(i);//输出i的值,因为此时i被赋值为10,所以输出的值为10;

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

输出结果.png
    var say = 0;// 定义了变量say,并且赋值say=0;
    (function say(n){ //创立了一个立即执行函数say,给了一个参数10,因为是立即执行函数所以有独立的作用域,不会与上面的全局变量say发生冲突;
        console.log(n);
        if(n<3) return;//进入if循环,输出n并且参数n-1,所以输出了10到2的数值;
        say(n-1);
    }( 10 ));
    console.log(say);//因为立即执行函数say执行完马上销毁,因此say的变量是全局变量say = 0,因此输出0

参考资料:
<a href="http://www.cnblogs.com/dolphinX/p/3280876.html">JavaScript作用域链</a>
<a href="https://www.zhihu.com/question/35832285">立即执行函数的意义</a>
<a href="https://www.sitepoint.com/back-to-basics-javascript-hoisting/">Back to Basics: JavaScript Hoisting(即变量提升机制)</a>

版权归饥人谷peter和饥人谷所有,若有转载,请注明来源

感谢吃瓜子观众:


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

推荐阅读更多精彩内容

  • 函数声明和函数表达式有什么区别 (*)解析器会率先读取函数声明,并使其在执行任何代码之前可以访问;函数表达式则必须...
    coolheadedY阅读 382评论 0 1
  • 工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式。简单...
    舟渔行舟阅读 7,705评论 2 17
  • 问答题 函数声明和函数表达式有什么区别 (*)答://函数声明function hello(){ conso...
    饥人谷_桶饭阅读 237评论 0 0
  • 1.函数声明和函数表达式有什么区别 (*) 函数声明 函数表达式 函数声明:函数调用可以发生在函数声明之前,例如下...
    TimeLesser阅读 386评论 4 4
  • 任务 函数声明和函数表达式有什么区别答:函数声明:function functionName(){}  函数表达式...
    mhy_web阅读 411评论 0 0