JS-函数和作用域

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

函数声明和函数表达式是声明函数的两种不同的方式,形式如下:

  • 函数声明:即使用function关键字声明一个函数
 //函数声明
 function sayHello(){
   console.log('hello')
 }

 //函数调用
 sayHello()

声明不必放到调用的前面,函数调用可以发生在函数声明之前,例如下面这种情况下不会报错

  printName();//输出console.log('1')
  function printName(){
    console.log('1');
  }
  //正常,因为提升了函数声明,函数调用可在函数声明之前

即在一个作用域下,var 声明的变量和function 声明的函数会前置

  • 函数表达式
  var sayHello = function(){
    console.log('hello');
  }

  sayHello()

声明必须放到调用的前面,例如

  printName();//浏览器提示Uncaught TypeError: printName is not a function(…)
  var printName = function(){
  console.log('1');
    };
  //报错,函数表达式和 var 一个变量没什么区别,变量printName还未保存对函数的引用,函数调用必须在函数表达式之后

浏览器提示Uncaught TypeError: printName is not a function(…).原因:类似变量提升,函数作为一个变量赋值给printName,等价于

  var printName;    //此时printName为undefined
  printName();
  printName = function(){
    console.log('1');
  };
  • 因此,函数声明和函数表达式不同之处在于:
    • Javascript引擎在解析javascript代码时会‘函数声明提升’(Function declaration Hoisting)当前执行环境(作用域)上的函数声明,而函数表达式必须等到Javascirtp引擎执行到它所在行时,才会从上而下一行一行地解析函数表达式,
    • 函数声明后面可以加括号立即调用该函数,函数表达式不可以,只能以fnName()形式调用

2.什么是变量的声明前置?什么是函数的声明前置

  • 变量声明前置
    • JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到当前作用域的头部,这就叫做变量的声明前置,也叫变量提升(hoisting)。
  • 函数声明前置
    • JavaScript引擎将函数名视同变量名,所以采用function命令声明函数时,函数声明会像变量声明一样,被提升到代码头部。因此,函数的调用可以写在声明前面,函数可以被执行。(注意:如下函数表达式,变量fn还未保存对函数的引用,函数调用必须在函数表达式之后)。
      console.log(fn); //undefined
      fn(); //浏览器提示Uncaught TypeError: fn is not a function(…)
    
      var fn = function(){}
      //报错,变量fn还未保存对函数的引用,函数调用必须在函数表达式之后
    

3.arguments 是什么

  • arguments是一个类数组对象,类似数组的方式,可以通过下标的方式去获取值,但它本身不是数组,没有数组的一些特性,所以叫类数组对象。在函数内部,可以使用arguments对象获取到该函数的所有传入参数。

    • 例如如下函数
      function printPersonInfo(name, age, sex){
        console.log(name);
        console.log(age);
        console.log(sex);
        console.log(arguments);
      }
    
    • 执行printPersonInfo('liu', 21, 'boy')后,输出:
      name : liu
      age : 22
      sex : boy
      ["liu", 22, "boy"]
    
    • 执行printPersonInfo('liu', 21,)后,输出:
      name : liu
      age : boy
      sex : undefined
      ["liu", "boy"]
    

4.函数的"重载"怎样实现

  • 重载是指不同的函数使用相同的函数名,但是函数的参数个数或类型不同。调用的时候根据函数的参数来区别不同的函数。
  • JS并不像其他强类型语言一样可以声明重载函数,若在原先声明的函数后再声明一个不同参数数量的函数(JS是弱语言,声明的函数不需要指明参数类型),解析器会用后面声明的函数覆盖前面声明的函数。

JS种没有重载! 同名函数会覆盖。但可以在函数体针对不同的参数调用执行相应的逻辑,如下

function printPeopleInfo(name, age, sex){
    if(name){
      console.log(name);
    }

    if(age){
      console.log(age);
    }

    if(sex){
      console.log(sex);
    }
  }
  printPeopleInfo('Byron', 26);
  printPeopleInfo('Byron', 26, 'male');

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

  (function(){ var a=1; })();
  (function(){ var a=1; }());  
  • 作用:

    • 作用:隔离作用域。
  • 参考

6.递归

  • 递归实现一个函数,计算 n!
  function factor(n) {
    if(n===1){
      return n
    }
    return n*factor(n-1)
  }

几个代码小题目

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('饥人谷', 2, '男');
  getInfo('小谷', 3);
  getInfo('男');
  • getInfo('饥人谷', 2, '男');输出:
  name:饥人谷
  age:2
  sex:男
  ["饥人谷", 2, "男"]
  name valley
  • getInfo('小谷', 3);输出:
  name:小谷
  age:3
  sex:undefined
  ["小谷", 3]
  name valley
  • getInfo('男');输出:
  name:男
  age:undefined
  sex:undefined
  ["男"]
  name valley

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

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

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

  console.log(a);//undefined
  var a = 1;
  console.log(b);//报错Uncaught ReferenceError: b is not defined(…)

a输出undefined是因为变量提升,b没有定义,类似如下代码

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

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

  sayName('world');   //输出 'hello ', 'world' 使用函数声明做出的声明前置
  sayAge(10);        //报错 Uncaught TypeError: sayAge is not a function(…) sayAge此时还为被赋值为函数
  function sayName(name){
    console.log('hello ', name);
  }
  var sayAge = function(age){
    console.log(age);
  };

作用域链

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

// 输出10

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

作用域链查找过程伪代码

/*
  1.
  globalContext = {
    AO:{
      x: 10
      foo:funcation(){}
      bar:funcation(){}
    }
    Scope: null
  }

  foo.[[scope]] = globalContext.AO
  bar.[[scope]] = globalContext.AO

  2.
  barContext = {
    AO:{
      x: 30
    }
    scope: bar.[[scope]] // globalContext.AO
  }
  3.
  fooContext = {
    AO:{}
    scope: foo.[[scope]] // globalContext.AO
  }

*/

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

// 输出30

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

作用域链查找过程伪代码

/*
  1.
  globalContext = {
    AO:{
      x: 10
      bar:funcation(){}
    }
    Scope: null
  }
  bar.[[scope]] = globalContext.AO

  2.
  barContext = {
    AO:{
      x: 30
      foo:funcation(){}
    }
    Scope: bar.[[scope]] // globalContext.AO
  }
  foo.[[scope]] = barContext.AO

  3.
  fooContext = {
    AO:{}
    Scope: foo.[[scope]] // barContext.AO
  }
*/

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

输出30

  var x = 10;
  bar() 
  function bar(){
    var x = 30;
    (function (){
      console.log(x)    // 30
    })()
  }
/*
  globalContext = {
    AO:{
      x: 10
      bar:funcation(){}
    }
    Scope: null
  }
  bar.[[scope]] // globalContext.AO

  2.
  barContext = {
    AO:{
      x: 30
      匿名函数A:funcation(){}
    }
    Scope: bar.[[scope]] = globalContext.AO
  }
  匿名函数A.[[scope]] // barContext.AO

  3.
  匿名函数AContext = {
    AO:{}
    Scope: 匿名函数A.[[scope]] // barContext.AO
  }
*/  

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()                //输出: undefined 5 1 6 20 
  console.log(a)      //输出: 200
/*
1.
  globalContext = {
    AO:{
      a: 1 -> 200
      fn:funcation(){}
      fn3:funcation(){}
    }
    Scope: null
  }
  fn.[[scope]] = globalContext.AO
  fn3.[[scope]] = globalContext.AO

  2.
  fnContext = {
    AO:{
      a: 5 -> 6 -> 20
      fn2:funcation(){}
    }
    Scope: fn.[[scope]] // globalContext.AO
  }
  fn2.[[scope]] = fnContext.AO

  3.
  fn3Context = {
    AO:{}
    Scope: foo.[[scope]] // globalContext.AO
  }

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

推荐阅读更多精彩内容

  • 一、函数声明和函数表达式 函数声明的形式:function fn() { } ,使用函数声明的形式声明一个函数时,...
    sutingy阅读 157评论 0 0
  • 一、函数声明function(){}是function +函数名字(){内容}调用函数是 函数名字();funct...
    崔敏嫣阅读 284评论 0 0
  • 函数声明和函数表达式 函数声明: fuction fn(){console.log("test");} 函数表达式...
    赵BW阅读 309评论 0 0
  • 函数声明和函数表达式有什么区别 用函数声明创建的函数可以在定义之前就进行调用(声明前置);而用函数表达式创建的函数...
    727上上上阅读 79评论 0 0
  • 1.函数声明和函数表达式有什么区别 (*) 区别: 函数声明后面的分号可加可不加,不加也不影响接下来语句的执行,但...
    Sheldon_Yee阅读 391评论 0 1