任务十七~函数

问答部分

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

  • 二者表示函数的方式不一样,如下
  • 函数声明(函数名称不可少)
function funName(){
              statement;
          }
  • 函数表达式(函数名称可以没有,末尾有一个分号)
var funName = function(){
             statement;
         };
  • 二者在函数名提升的时候不一样(函数名提升是指JS引擎在解析代码时,整个函数会像变量提升一样提到代码头部,但此时并未执行
  • 对于函数声明,如下代码
printName("jirengu");
function printName(name){
       console.log(name);
  }

此时显示的结果如下图所示

函数名提升

此时执行调用函数时不会报错,因为函数名的提升,整个函数被提升到代码头部

  • 对于函数表达式,如下代码
printName("jirengu");
var printName = function(name){
          console.log(name);
 };

此时显示结果如下图所示


函数表达式

这个时候会报错是因为此时JS引擎是如下处理代码的

var printName;
printName("jirengu");
printName = function(name){
            console.log(name);
   };

以上代码中,第一行表示函数变量声明提前,但还未被赋值,等于undefined;所以在执行第二行时则会发生错误;即函数表达式只是函数声明提前,但是函数部分并未提前


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

  • 变量的声明前置是指Javascript引擎解析代码,获取所有被声明的代码变量,然后再一行一行的执行。这样造成的结果是所有变量的声明语句,都将被提升到代码头部,如下情况
console.log(a);
var a = 1;

此时并不会报错,结果如下图所示


变量的声明前置

JS引擎在解析代码时相当于以下过程

var a;//变量声明提升到代码头部
console.log(a);
a = 1;
  • 函数声明前置指JS引擎在解析代码时,整个函数会像变量提升一样提到代码头部,如下情况
printNumber(12);
function printNumber(num){
    console.log(num);
 }

此时不会报错,显示结果如下图所示


函数声明前置

此过程相当于一下代码

function printNumber(num){
    console.log(num);
 }//函数声明前置会让整个函数提到代码头部
printNumber(12);

还有函数表达式的前置,见问题1


三、arguments 是什么?

  • arguments~函数运行时,有时需要提供外部数据,不同的外部数据会得到不同的结果,这种外部数据即为参数,比如如下代码
function getSquare(x){
     return x * x;
}
console.log(getSquare(4));//16

其中x即为getSquare函数的参数,每次运行getSquare函数时,都要提供x值,否则不会得到结果

  • arguments不是必须的,JS中允许省略arguments,被省略的参数的值就变为undefined
  • 函数体内可以通过arguments对象来访问这个数组,从而获取传递给函数的每一个参数,如下代码
function visitArg(){
                console.log(arguments[0]);
                console.log(arguments[1]);
                console.log(arguments[2]);
            }
 visitArg("ji","ren","gu");

显示结果如下图


arguments对象获取函数的参数
  • 通过访问arguments对象的length属性可以获知有多少个参数传递给了函数,如下
function howmanyArg(){
     console.log(arguments.length);
}
howmanyArg(1,2,3,4);
howmanyArg(12);
howmanyArg();
howmanyArg("hello",4,false);

输出结果为下图所示


arguments.length

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

  • 在一些语言中(如Java)中,相同名字的函数参数个数不同或者顺序不同都被认为是不同的函数,称为函数重载。但是在Javascript中没有函数的重载
  • 在Javascript中可以通过arguments来实现函数的重载,如下代码
function sum(){
    var x = 0;
    for(var i = 0;i < arguments.length;i++){
             x += arguments[i];
     }
     return x;
  }
  console.log(sum(1,2,3));//6

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

  • 立即执行函数模式(没有声明前置)是一种语法,可以让你的函数在定义后立即被执行,这种模式本质上就是函数表达式(命名的或者匿名的),在创建后立即执行,其代码格式如下
//在最前最后加括号
(function atOnce(){
           console.log("abc");
}());
//在function外面加括号
(function atOnce(){
           console.log("abc");
})();
  • 立即执行函数表达式的作用:
  • 立即执行函数模式被广泛使用,它可以帮你封装大量的工作而不会在背后遗留任何全局变量
  • 定义的所有变量都会成员立即执行函数的局部变量,所以你不用担心这些临时变量会污染全局空间
  • 这种模式经常被使用在书签工具(bookmarklets)中,因为书签工具在任何页面上运行并且保持全局命名空间干净是非常必要的
  • 这种模式也可以让你将独立的功能封装在自包含模块中
    更多知识

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

  • 函数的作用域链~任何程序设计语言都有作用域的概念,简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。在JavaScript中,变量的作用域有全局作用域和局部作用域两种
  • 全局作用域~在代码中任何地方都能访问到的对象拥有全局作用域,一般来说以下几种情形拥有全局作用域
  • 最外层函数和在最外层函数外面定义的变量拥有全局作用域,如下
var num = 1;
function example(){
  var ourAuthor = "jirengu";
  function printName(){
      console.log(ourAuthor);
  }
  printName();
 }
//在这段代码中,变量num和函数example是拥有全局作用域;
而在函数example里面的变量和函数并不拥有全局作用域
  • 所有末定义直接赋值的变量自动声明为拥有全局作用域,如下
 function example(){
 var a = "jirengu";
 b ="quanju";
 console.log(a);
}
//在以上代码中,变量b拥有全局作用域;而变量a则不是
  • 所有window对象的属性拥有全局作用域
  • 局部作用域~和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,最常见的例如函数内部,所有在一些地方也会看到有人把这种作用域称为函数作用域
  function example(){
    var author = "jirengu";
    function printName(){
        console.log(ourAuthor);
    }
    printName();
   }
//在以上代码中,变量author和函数printName都只拥有局部变量
  • 作用域链~在JavaScript中,函数也是对象,实际上,JavaScript里一切都是对象。函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是[[Scope]],由ECMA-262标准第三版定义,该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问(如果变量在该作用域中没有,则它会逐级向上寻找,直至最顶层)
  • 以上内容引用自JavaScript 开发进阶:理解 JavaScript 作用域和作用域链

代码部分

一、以下代码输出什么?

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

在chrome上运行如下图所示


代码1运行效果图

二、写一个函数,返回参数的平方和?

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

在chrome中一下效果图


代码2运行效果图

三、如下代码的输出?为什么?

console.log(a);//输出结果为undefined
var a = 1;//输出结果为1
console.log(b);// Uncaught ReferenceError: b is not defined

造成以上结果的原因是变量提升,即JS引擎在解析代码时会把所有的变量声明提到代码头部,再一行一行的执行代码,所以第一行代码输出结果为undefined;而第三行代码是因为b并不是变量,所以会报错;以上代码相当于以下过程

var a;//变量声明提升
console.log(a);
a = 1;
console.log(b);

四、如下代码的输出?为什么?

sayName('world');
sayAge(10);
function sayName(name){
    console.log('hello ', name);
}
var sayAge = function(age){
    console.log(age);
};

以上代码的输出结果为

//sayName("world");输出结果为hello world
//sayAge(10);输出结果为Uncaught TypeError: sayAge is not a function

第一行代码由于函数声明提升,整个sayName函数提到代码头部,则在执行sayName("world")时输出正常结果;第二行代码由于sayAge是函数表达式,则js引擎在解析代码时,只是把var sayAge提到代码头部,并未把整个函数部分提到代码头部,所以在执行时会报错,以上内容相当于以下过程

function sayName(name){
    console.log('hello ', name);
}//函数声明前置将整个函数提到代码头部
var sayAge;//函数表达式只是把var sayAge提到代码头部
sayName('world');//输出结果为hello world
sayAge(10);//sayAge并不是一个函数,则会报错
sayAge = function(age){
    console.log(age);
};//将右边的函数赋值给sayAge

五、如下代码的输出?为什么?

function fn(){}
var fn = 3;
console.log(fn);//输出结果为3

由于变量声明前置和函数声明前置,以上代码相当于一下过程

var fn;//变量声明前置,将var fn提到代码头部
function fn(){}//函数声明前置
fn = 3;//将数值3赋值给fn
console.log(fn);//最终输出结果为3

六、如下代码的输出?为什么?

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

最终出现的结果是

//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;//变量声明提升
    function fn2(){
         console.log('fnnn2');
     }//函数声明提升
    console.log(fn2);//输出结果为fn2函数
    fn = 3;//fn被重新赋值
    console.log(fn2);//输出结果为3
    console.log(fn);//输出结果为fn函数
 }
fn(10);

七、如下代码的输出?为什么?

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

以上代码输出结果为

//console.log(fn(fn));
Uncaught TypeError: fn is not a function

出现以上结果是因为JS引擎在解析代码时做了以下事情

var fn;//变量声明提升
function fn(fn){
     console.log(fn);
}//函数声明提升
fn = 1;//把数值1赋值给函数fn
console.log(fn(fn));//会报错,因为fn不是函数,已经被赋值为1

八、如下代码的输出?为什么?

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

最终输出结果为

console.log(i);//输出结果为10
console.log(j);//输出结果为100

相当于以下过程

var i;//变量提升,将var i提到代码头部
var j;//变量提升,将var j也提到代码头部
console.log(i);//undefined,此时变量i还未赋值
console.log(j);//undefined,此时变量j也还未赋值
for(var i=0;i<10;i++){
     var j = 100;
}
console.log(i);//在for循环里执行完后,i为10
console.log(j)//在for循环执行后,j被赋值为100

九、如下代码的输出?为什么 ?

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;//变量提升,将var i提到代码头部
var fn;//变量提升,将var i提到代码头部
function fn(){
    var i;//函数体内部的变量提升
    function fn2(){
        i = 100;
    }//函数体内部的函数声明提升
    console.log(i);//undefined,因为此时的i只是声明,但是还未赋值
    i = 99;//把99赋值给变量i
    fn2();//执行fn2函数,执行完后结果是i的值为100
    console.log(i);//100
}//函数声明提升,将整个函数提到代码头部
fn();//执行函数fn,执行完后,得到undefined和100l两个结果
i = 10;//把10赋值给ifn = 20;//把20赋值给fn
console.log(i);//10

十、如下代码的输出?为什么?

var say = 0;
(function say(n){
    console.log(n);
    if(n<3) return;
    say(n-1);
}( 10 ));
console.log(say);

最终输出结果如下图


代码10运行效果图
  • 首先,立即执行函数时没有函数声明前置的,则以上代码会按照顺序来执行,解释如下
var say = 0;//把0赋值给变量say
(function say(n){
    console.log(n);//输出给定的参数n~10,9,8,7,6,5,4,3,2
    if(n<3) return;//当n<3时,跳出函数,故当n为2时跳出函数
    say(n-1);
}( 10 ));
console.log(say);//输出为0,因为立即执行函数执行完了就完了,这里是变量say

版权声明:本教程版权归邓攀和饥人谷所有,转载须说明来源!!!!

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

推荐阅读更多精彩内容

  • 函数声明和函数表达式有什么区别 (*)解析器会率先读取函数声明,并使其在执行任何代码之前可以访问;函数表达式则必须...
    coolheadedY阅读 383评论 0 1
  • 工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式。简单...
    舟渔行舟阅读 7,717评论 2 17
  • 1.函数声明和函数表达式有什么区别 (*) 区别: 函数声明后面的分号可加可不加,不加也不影响接下来语句的执行,但...
    Sheldon_Yee阅读 396评论 0 1
  • 一、函数声明和函数表达式有什么区别?(*) ECMAScript里面规定了三种声明函数的方式: 构造函数函数也是对...
    婷楼沐熙阅读 452评论 0 2
  • Define: .new promise传入的函数里面是立即执行的 . promise 是一个对象,里面有三个状态...
    享悦moonlight阅读 356评论 0 0