函数与作用域

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

  • 函数声明:
    形式上 function fuctionName(){//statement};声明了一个名字为functionName的函数,浏览器解析的时候,先要做函数声明前置,在globlecontext的AO中,声明此函数,此时,你在全球作用域下(包括函数声明之前的位置)调用,都可以找到这个函数。

  • 函数表达式:
    形式上 var someThing=fuction (){//statement};虽然这也是声明了一个函数(匿名的),但实际上浏览器解析的时候,先做的是变量提升,在globlecontext的AO中,声明的是一个变量,假如,在函数声明之前调用该函数,是不能够找到这个函数的,因为调用的时候必然要调用的someThing这个变量,但是变量值在提升变量的时候未给出。

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

  • 变量的声明前置:
    变量的声明前置就是在函数内部,首先要做的事也是类似于浏览器做变量提升,先在当前上下文的AO中声明这个变量。

  • 函数的声明前置:
    函数的声明前置是,当我们用函数声明来声明一个函数时,函数就会在至当前上下文的AO中声明这个这个函数,同时,在函数内部的上下文的scope中,给声明的函数开辟一个空间,并指向父元素的AO.

3.arguments是什么?

  • arguments是一个伪类数组,目前仅仅知道,他是一个函数内部自带的一个类似于数组的参数,我们可以调用arguments[],来获取传入函数内部的参数,并且支持索引,支持length属性。

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

  • 首先,JS中不同于其他语言,没有重载,例如其他语言中,我们可以设定。但是我们可以控制函数体内部的逻辑语句来实现重载。

例如:

<script language="JavaScript"> 
function f(length) 
{ 
    alert("高为:"+length); 
} 

function f(length,width) 
{ 
    alert("高为:"+length+",宽为:"+width); 
} 
</srcipt>
/* 上面这个段代码行不通,第一个函数会被第二个覆盖,不能实现 f(10)想要的效果。*/

但是我们可以这么做

<script language="JavaScript"> 
function f(length) 
{ 
    var len= arguments.length; 
    if(1 == len) 
    { 
        var width = arguments[1]; 
        alert("高为:"+length+",宽为:"+width); 
    } 
    else 
    { 
        alert("高为:"+length); 
    } 
} 
</srcipt>

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

  • 立即执行表达式是什么?
    (function (){})();
    (function(){}());
    上面就是两个常见的立即执行表达式,当我们建立一个匿名函数时,并希望他执行时,我们想到可以这样 function (){}(); 但是实际上,语法上不对,因为浏览器读到这里时,会认为这是一个函数声明,但是没有给出函数名字,所以会报错。但是我们在 function (){}加上括号,意义就不一样了,因为JS中小括号内部是一个表达式,表达式后面加括号,函数可以立即执行的, 和函数表达式声明一样
var something= functiong (){
  console.log ( "hello")
}();

所以,我们只需要让浏览器明白,我们前面function (){} 是一个函数表达式就可以了,类似的方法有许多,而已加上各种运算符,让浏览器知道,我们这是一个函数表达式,这就可以了。类似的有很多。

  • 为什么要用立即执行函数表达式?

    因为JS并没有块级作用域的概念,你在全局或者局部声明的变量 极有可能会被自己或者他人覆盖掉,为了保护这些的变量,我们可以给他加上一层外壳,封装起来,这样,外部变量就不会对内部的变量造成影响了。

求n!,用递归来实现

function doRecursion(n){
    if(n<0){
      console.log('You input a wrong number');
    }
    else if(n===0||n===1){
        return 1;
    }
    else if(n>0){
      return n*multiply(n-1);
    }
}

7.以下代码输出什么?

    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('男');

// 倒数第三行调用函数 ,输出 name: 饥人谷,age:2,sex:男;['饥人谷',2,'男‘],name:valley
// 倒数第二行调用函数,输出 name:小谷,age:3;sex:undefined;['小谷',3,];name:valley;
//最后一行调用函数,输出name:男,age:undefined;sex:undefined;['男'];
name:valley;

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

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

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

    console.log(a); //undefined,变量提升,有变量a,但是没有值。
    var a = 1;
    console.log(b);//error ,没有定义这个变量。

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

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

第一个函数能输出是因为,函数声明前置,可以找到globleContext的OA中有这个函数,然后就可以去执行这个函数的上下文。
第二个变量提升,浏览器不知道sayAge(10)是什么意思,如果放在函数表达式后面,浏览器就知道原来这个sayAge()是一个函数表达式,就会执行了。

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

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

第一步:

globleContext{
  A0:{
  x:10,
  function foo(),
  bar(),
  }
  scope:null;
}
foo().[[scope]]=globleContext.AO
bar().[[scope]]=globleContext.AO

第二步:

执行bar();
在globloContext.AO中找到了 bar();
调用bar();进入bar()函数的barContext
barContext:{
  AO:{
    x:30,
  }
  scope:globleContext.AO
}
barContext.AO中没有找到 foo();然后去scope中找,scope指向globleContext.AO, 找到右foo();调用foo();
fooContext:{
  AO:{
    x:undefined,
  }
  scope:globleContext.AO
}
执行console.log(x);
但是在AO中没有找到,去scope中找到指向globleContext.AO,找到x的值为10,所以,最终结果就是10。

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

var x = 10;
bar() 
function bar(){
  var x = 30;
  function foo(){
    console.log(x) 
  }
  foo();
}   
globleContext: {
  AO:{
    x:10,
    function bar(),
  }
  scope:null
}

bar.[[scope]]=globleContext.AO;

//第二部;
执行bar(); 在globleContext中找到。
进入bar();

barContext:{
  AO:{
    x=30;
    function foo();
  }
  scope:globleContext.AO
}

foo.[[scope]]=barContext.AO;

执行 foo(); 
foo()中没有找到x.去barContext.AO找到了。所以console.log(x);
结果是10。

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

var x = 10;
bar() 
function bar(){
  var x = 30;
  (function (){
    console.log(x)
  })()
}
1、执行bar(),globleContext中有bar()
2 、进入bar()的上下文;
3、执行立即执行函数表达式,但是函数表达式AO中没有找到X,
4、去scope中找,找到的是barContext.AO中,有x的值,得到30.

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

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()
console.log(a)
1、执行fn() 在globleContext中找到了,所以,进入fn()的上下文。
2、console.log(a),当前函数的作用域中有a变量,此时没有赋值//输出 **undefined**
3、再次执行console.log(a),上一行,a已经赋值,所以//输出 **5**
4、a++ ; a=6,不用输出。
5、var a, a仍然等于6.
6、执行fn3() ,当前函数的AO中没有,找到globleContext.AO,有fn3(),进入fn3()的上下文中。
7、console.log(a),当前的AO还没有a,所以,去找到上一级的AO,找到globleContext.AO,然后,得到结果// **1**,顺便,修改了globleContext.AO中的a=200;
8、回到fn(),运行fn2(),找到了fn2(),进入fn2(), console.log(a), 当前AO中没有a,找到上一级也就是fn的AO中,a=6 ,所以输出 ** 6 ** ,顺便修改了fnContext中的AO,是20 。
9、执行fn()中的console.log(a),此时受到第8步骤的影响,所以,输出是**20.**
10 、fn()运行结束,此时,再次运行console.log,受到第7 的影响,a变为了200.所以输出**200**
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容

  • 函数声明和函数表达式有什么区别? 函数声明和函数表达式是EMACScript规定的两种不同的声明函数的方法。1.函...
    LeeoZz阅读 341评论 0 1
  • 1. 函数声明和函数表达式有什么区别 函数声明和函数表达式都是声明函数的方式 区别1 写法:函数声明 : fu...
    怎么昵称阅读 266评论 0 0
  • 1,函数声明和函数表达式有什么区别 1、背景介绍 定义函数的方法主要有三种: 1:函数声明(Function De...
    进击的前端_风笑影阅读 427评论 0 0
  • 函数声明和函数表达式有什么区别 函数声明:function fn(){}; 函数表达式: var fn = fun...
    cross_王阅读 255评论 0 0
  • 1. 函数声明和函数表达式有什么区别 使用function关键字声明一个函数时,声明不必放到调用的前面。//函数声...
    _李祺阅读 261评论 0 0