JS函数与作用域

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

在ECMAScript中,有两个最常用的创建函数对象的方法,即使用函数表达式或者使用函数声明。对此,ECMAScript规范明确了一点,即是,即函数声明 必须始终带有一个标识符(Identifier),也就是我们所说的函数名,而函数表达式则可以省略。

  • 什么是 Function Declaration(函数声明)?
    Function Declaration 可以定义命名的函数变量,而无需给变量赋值。Function Declaration 是一种独立的结构,不能嵌套在非功能模块中。可以将它类比为 Variable Declaration(变量声明)。就像 Variable Declaration 必须以“var”开头一样,Function Declaration 必须以“function”开头。

    ECMA 5(13.0)定义语法:
    Function Identifier ( FormalParameterList[opt] ) { FunctionBody }

function bar() {
        return 3
    }
bar();//3
bar;// function
  • 什么是 Function Expression(函数表达式)?
    Function Expression 将函数定义为表达式语句(通常是变量赋值)的一部分。通过 Function Expression 定义的函数可以是命名的,也可以是匿名的。Function Expression 不能以“function”开头(下面自调用的例子要用括号将其括起来)。
//anonymous function expression
var a = function() {
 return 3;
}
  
//named function expression
var a = function bar() {
 return 3;
}
  
//self invoking function expression
(function sayHello() {
 alert("hello!");
})();

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

这里引用 Ben Cherry的话:“Function declaration和function variable(函数变量)通常会被 JavaScript 解释器移(‘hoisted')到当前作用域顶部”。对于variable(变量)也是如此。

  • 变量声明前置:JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,然后线性运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部。
console.log(a);
    var a = 1;
    //var a;
    //console.log(a); undefined;
    //a =1;
  • 函数声明前置:JavaScript引擎将函数名视同变量名,所以采用function命令声明函数时,整个函数会像变量声明一样,被提升到代码头部。
bar();// 4
function bar() {
 return 4;
    };

arguments 是什么?

  • arguments对象包含了函数运行时的所有参数,arguments[0]就是第一个参数,arguments[1]就是第二个参数,以此类推。这个对象只有在函数体内部,才可以使用。
var argumentTest = function() {
        console.log(arguments[0]);
        console.log(arguments[1]);
        console.log(arguments[2]);
    };
argumentTest(1,2,3);
//1
//2
//3

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

  • 重载是很多面向对象语言实现多态的手段之一,在静态语言中确定一个函数的手段是靠方法签名——函数名+参数列表,也就是说相同名字的函数参数个数不同或者顺序不同都被认为是不同的函数,称为函数重载。
  • 在JavaScript中没有函数重载的概念,函数通过名字确定唯一性,参数不同也被认为是相同的函数,后面的覆盖前面的,但可以在函数体针对不同的参数调用执行相应的逻辑。
function printPeopleInfo (name, age, sex){
    if(name){
      console.log(name);
    }
    if(age){
      console.log(age);
    }
    if(sex){
      console.log(sex);
    }
    }
  printPeopleInfo("Byron", "male");// "Byron", "male"
  printPeopleInfo("Byron", 26, "male");//"Byron", 26, "male"

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

函数定义后如果不调用其不会被执行。而立即执行函数指定义函数后立即执行函数。其作用是隔离作用域减少对全局作用域的污染。常见的形式有:

(function(){var a =1;})();
var i = function(){return 10;}();
true && function(){return 10;}();
0, function(){return 10;}();

求n!,用递归来实现?

程序调用自身的编程技巧称为递归( recursion)。

function recursion(n) {
        if(n === 1 || n === 0) {
            return 1;
        }else {
            return n*recursion(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, '男'); 
  // 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 = 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.
/*原因,解析器解析过程。
var a; // undefined.
console.log(a);  //undefined.
a = 1;
console.log(b); b没声明也没赋值,所有报错,b is not defined
 */

代码题目4, 如下代码的输出?为什么?

sayName('world');//输出结果 hello world.
sayAge(10);// TypeError: sayAge is not a function.
function sayName(name){
console.log('hello ', name);
    }
var sayAge = function(age){
console.log(age);
    };  
/*
解析过程。
函数,变量在作用域前置。
function sayName(name){
console.log('hello ', name);
    }
var sayAge;// undefined.
sayName('world'); //输出结果 hello world.
sayAge(10); // TypeError: sayAge is not a function.
sayAge = function(age){
console.log(age);
    };  
 */

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

var x = 10
bar() // 10
function foo() {
  console.log(x)
}
function bar(){
  var x = 30
  foo()
}
/*
解析过程
globalContext = {
    AO:{
        x:10
        foo:function
        bar:function
    },
    Scope:null
}

//foo()声明时
foo.[[scope]] = globalContext.AO
//bar声明时
bar.[[scope]] = globalContext.AO
//调用bar时,bar的执行上下文
barContext = {
    AO:{
     x:30
     foo:function
    }
    scope:bar.[[scope]] = globalContext.AO
}
//调用foo时,先从bar的AO中,找不到再从scope中找,这里在barConetext中能够找到
,就立即调用。
//调用时进入foo的执行上下文
fooContext = {
    AO:{    
     x:10;
    }
    scope:foo.[[scope]] = globalContext.AO
}
//所以从scope中即globalContext.AO中可以找到x:10。
 */

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

var x = 10;
bar(); // 30 
function bar(){
  var x = 30;
  function foo(){
    console.log(x) // 30
  }
  foo();
}   
/*解析过程
全局作用域
globalContext = {
    AO: {
    x: 10,
    bar: function
    }
    scope =  null
}
//调用bar()的时候,bar的执行上下文是 bar[[scope]] = globalConext
barContext = {
    AO: {
    x: 30,
    foo: function
    }
    bar[[scope]] = globalConext.AO
}
//调用foo的时候,foo的执行上下文是 foo[[scope]] = barContext
fooConext = {
    AO: {
    x: 30 //只能从上一个作用域找
    }
    foo[[scope]] = barContext.AO
}
//foo()输出的结果为30,foo()的作用域属于bar()。
所以bar()里面的函数执行结果为30,bar()为30。
 */

代码题目7, 如下代码输出什么? 写出作用域链查找过程伪代码。

var x = 10;
bar() // 30
function bar(){
  var x = 30;
  (function (){
    console.log(x)// 30
  })()
}
/*解析过程
globalContext = {
    AO: {
    x : 10,
    bar : function
    }
    scope = null
}

barContext = {
    AO: {
    x: 30
    function() {}
    }
    bar[[scope]] = globalConext.AO
}

functionContext= {
    AO: {
    x: 30 //x为30, 只能从bar里找活动对象。
    }
    function[[scope]] = barConext.AO
}
所以(function (){console.log(x)})为30,同时返回给它的上文bar (),所以bar()为30。
 */

代码题目8, 如下代码输出什么? 写出作用域链查找过程伪代码。

var a = 1;
function fn(){
  console.log(a)//undefined
  var a = 5
  console.log(a)//5
  a++//6 
  var a
  fn3()
  fn2()
  console.log(a)//20
  function fn2(){
    console.log(a)//6
    a = 20
  }
}
function fn3(){
  console.log(a)//1
  a = 200
}
fn();
console.log(a);//200
/*
解析过程
1. globalContext = {
    AO: {
    a: 1, ==> 200
    fn: function,
    fn3: function
    },
    scope = null
}
fn[[scope]] = globalConext, fn3[[scope]] = globalConext.

2. fnContext = {
    AO: {
    a: 5, ==>6 ===>20 
    fn2: function
    }
    fn2[[scope]] = fnContext.AO
}

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

推荐阅读更多精彩内容

  • 1.函数声明和函数表达式有什么区别 函数声明 代码执行时函数声明会被提升到最前执行,所以函数的调用与函数声明的顺序...
    Feiyu_有猫病阅读 367评论 0 0
  • JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里。 函数声明和函数表达式有什么区...
    毕子歌阅读 374评论 0 0
  • 1.函数声明和函数表达式有什么区别 函数声明可以看作是函数的初始化,我们将给函数传参并建立函数体的表达式,当我门建...
    高进哥哥阅读 209评论 0 0
  • 函数声明和函数表达式有什么区别 JavaScript 中需要创建函数的话,有两种方法:函数声明、函数表达式,各自写...
    萧雪圣阅读 943评论 2 2
  • 应朋友之邀,设计了这几款《权利的游戏》主题T恤,在第七季结束之前,以这种特殊的方式作为纪念。希望你们能喜欢,嘿嘿
    丑丑苑阅读 307评论 0 0