定义函数的方法

定义函数的方法主要有三种:

  1. 函数声明(Function Declaration)
  2. 函数表达式Function Expression)
  3. new Function构造函数

其中,经常使用的是函数声明和函数表达式的函数定义方法,这两种方法有着很微妙的区别和联系,而且这两种方法的使用也容易混淆,所以这篇文章主要总结下这两种函数定义方法的相关知识点,当然本文的主题依然是关于函数提前的。

函数声明的典型格式:

function functionName(arg1, arg2, ...){<!-- function body -->
}

函数表达式

  • 函数表达式的典型格式:

    var  variable=function(arg1, arg2, ...){<!-- function body -->
    }
  • 包含名称(括弧,函数名)的函数表达式:

    var  variable=function functionName(arg1, arg2, ...){<!-- function body -->
    }

    像上面的带有名称的函数表达式可以用来递归:

    var  variable=function functionName(x){if(x<=1)return 1;elsereturn x*functionName(x);
    }

声明提前

声明提前是函数声明和函数表达式的一个重要区别,对于我们进一步理解这两种函数定义方法有着重要的意义。

变量在声明它们的脚本或函数中都是有定义的,变量声明语句会被提前到脚本或函数的顶部。但是,变量初始化的操作还是在原来var语句的位置执行,在声明语句之前变量的值是undefined。

上面的结论中可以总结出三个简单的点:

  1. 变量声明会提前到函数的顶部;
  2. 只是声明被提前,初始化不提前,初始化还在原来初始化的位置进行初始化;
  3. 在声明之前变量的值是undefined。

看一个例子。

var aerchi='aerchi';
function aerchiToShow(){debugger;console.log(aerchi); //aerchi
}
aerchiToShow();// aerchi

上面代码正确的输出结果是:aerchi

再看下面的例子

var aerchi='aerchi';
function aerchiToShow(){debugger;console.log(aerchi); // undefined var aerchi='aerliho';console.log(aerchi); //aerliho
}
aerchiToShow();
// undefined
// aerliho

上面代码正确的输出结果是:
先输出undefined,然后输出aerliho

注: 在声明之前变量的值是undefined,只是声明被提前,初始化并未提前,初始化还在原来初始化的位置进行初始化.

函数声明

   函数声明创建将来代码调用的函数。函数可以在声明之前的位置被调用。示例如下:   

//可以在声明之前的位置被调用
var size=show("call before function");
function show(str){  console.log(str);
};
//可以在声明之后的位置被调用
var size2=show("call after function");  

函数表达式

将函数放在本该表达式待的位置,这称为函数表达式。在函数表达式中,经常使用匿名函数。示例如下:     

//会报错,变量aa 还未保存对函数的引用,函数调用必须在函数表达式之后
var aa = showM("call before function");
var showM = function(str){  console.log(str);
};
//VM3235:1 Uncaught TypeError: showM is not a functionat <anonymous>:1:10
var showM = function(str){  console.log(str);
};
//只能在函数表达式定义之后被调用
var bb = showM("call after function");  


函数表达式相当于是是把函数对象赋值给一个变量。

对于函数表达式,变量赋值是不会提前的,即function(arg1, arg2, ...){<!-- function body -->}是不会提前的,所以函数定义并没有被执行,所以函数表达式不能像函数声明那样进行函数声明提前。

立即执行函数(IIFE)

   没有名称,在解释器经过它们时执行一次。示例如下:   

var showM = (function(str){  console.log(str);
})("call me from function");
16:38:45.542 VM1255:2 call me from function
16:38:45.556 undefined
16:39:30.972 (function(str){  console.log(str);
}("call me from function 2"));
16:39:30.971 VM1257:2 call me from function 2
16:39:30.994 undefined
16:39:44.131 !function(str){  console.log(str);
}("call me from function 2");
16:39:44.131 VM1259:2 call me from function 2
16:39:44.145 true

            //情况1  //结果会被输出  var fn=function(){  console.log("函数表达式赋值给一个变量");  }();  //情况2  //结果不会被输出,JavaScript引擎只解析函数声明,忽略后面的括号,函数声明不会被调用  function fn(){  console.log("函数声明");  }();  //情况3, 会输出:函数声明(function fn(){  console.log("函数声明");  })();  //情况4  //语法错误,匿名函数属于函数表达式,未执行赋值操作,不能被调用  function(){  console.log("函数表达式");  }();  //Uncaught SyntaxError: Function statements require a function name//情况5//输出  (function(str){  console.log(str);  })("函数表达式");

经典的立即执行函数样式

(function(a){  console.log(a); })(123);  //123
(function(a){  console.log(a); }(1234));  1234
!function(a){  console.log(a); }(12345);  //12345
+function(a){  console.log(a); }(123456);  //123456
-function(a){  console.log(a); }(1234567);  //1234567
//而加上(),!,+,-等符号可以执行,是因为加上这些符号就可以告诉JavaScript引擎这不是函数声明了

注意:

只有函数表达式才能实现立即执行,匿名函数也是函数表达式为何不能立即执行呢,因为匿名函数开始的function会被JavaScript引擎识别为函数声明的开始,所以加上括号也不会被执行,而加上(),!,+,-等符号可以执行,是因为加上这些符号就可以告诉JavaScript引擎这不是函数声明了。

函数声明、 函数表达式的执行顺序

函数声明:

1 function 函数名称 (参数:可选){
函数体
}

函数表达式:

1 function 函数名称(可选)(参数:可选){
函数体
}
function foo(){} // 声明,因为它是程序的一部分
var bar = function foo(){}; // 表达式,因为它是赋值表达式的一部分new function bar(){}; // 表达式,因为它是new表达式(function(){function bar(){} // 声明,因为它是函数体的一部分
})();
function foo(){} // 函数声明
(function foo(){}); // 函数表达式:包含在分组操作符内try {(var x = 5); // 分组操作符,只能包含表达式而不能包含语句:这里的var就是语句
} catch(err) {// SyntaxError
}

来看一个函数声明、 函数表达式的执行顺序的例子

var getName = function () { console.log('var getName 1');
};
function getName() { console.log('function getName 1');
}//下面的 getName 由于与最上的相同,故被重新赋新值
var getName = function () { console.log('var getName 2'); //此函数表达式会被执行
};
function getName() { console.log('function getName 2');
}
getName();

上述代码的执行结果是:var getName 2
原因是这样的,var声明的变量和函数声明function都会被提升,但是函数声明的提升的级别是比var要高的.

另一个示例:

var currying = function(fn) {// fn 指官员消化老婆的手段var args = [].slice.call(arguments, 1);// args 指的是那个合法老婆return function() {// 已经有的老婆和新搞定的老婆们合成一体,方便控制var newArgs = args.concat([].slice.call(arguments));// 这些老婆们用 fn 这个手段消化利用,完成韦小宝前辈的壮举并返回return fn.apply(null, newArgs);};
};// 下为官员如何搞定7个老婆的测试
// 获得合法老婆
var getWife = currying(function() {var allWife = [].slice.call(arguments);// allwife 就是所有的老婆的,包括暗渡陈仓进来的老婆console.log(allWife.join(";"));
}, "合法老婆");// 获得其他6个老婆
getWife("大老婆","小老婆","俏老婆","刁蛮老婆","乖老婆","送上门老婆");
//合法老婆;大老婆;小老婆;俏老婆;刁蛮老婆;乖老婆;送上门老婆// 换一批老婆
getWife("超越韦小宝的老婆");
//合法老婆;超越韦小宝的老婆

本文地址: https://blog.csdn.net/aerchi/article/details/79805301

[乐意黎原创]JS函数声明、 函数表达式与立即执行函数的理解与执行顺序相关推荐

  1. [乐意黎原创] JS根据useAgent来判断edge, ie, firefox, chrome, opera, safari 等浏览器的类型及版本

    JS根据浏览器的useAgent来判断浏览器的类型. userAgent 属性是一个只读的字符串,声明了浏览器用于 HTTP 请求的用户代理头的值. javascript语法:navigator.us ...

  2. JS基础篇--函数声明与定义,作用域,函数声明与表达式的区别

    Scoping & Hoisting 例: var a = 1;function foo() {if (!a) {var a = 2;}alert(a); };foo(); 上面这段代码在运行 ...

  3. [乐意黎原创] WebPack 打包时抛Uncaught Error: Cannot find module '.\dist\bundle.js'

    如题:WebPack 打包时抛Uncaught Error: Cannot find module '.\dist\bundle.js' A. Webpack 命令时抛错 B.运行时Chrome 控制 ...

  4. c语言函数声明定义参数命名,C语言函数声明与定义

    C语言函数声明与定义教程 在 C语言函数声明与定义 语法 type funcName(paramType1 param1, paramType2 param2){ // 执行语句... return ...

  5. [乐意黎原创] 删除QQ的MiniBrowser浏览器,QQ聊天会话中点击链接直接用默认浏览器中打开

    [乐意黎原创] 删除QQ自带的MiniBrowser浏览器,使从聊天会话中点击链接直接打开默认浏览器中打开 如题,不知从什么版本开始,乐-意-黎无意中发现,点击QQ聊天会计中的链接时,不会在默认浏览器 ...

  6. [乐意黎原创]PHP启用session后抛 session_start(): open(/var/lib/php/session/sess_... 的解决办法

    如题,PHP启用SESSION后抛 Warning: session_start(): open(/var/lib/php/session_user/sess_d5gn9q7q9qii26ajk2c8 ...

  7. [乐意黎原创] 2014年全国和云南省中级会计师成绩、分数段、过关率及年龄段统计分析

    2014年全国会计资格考试报名人数达214万人,比2013年度增长3.88%. 其中: 初级资格为137.1万人,比去年增长了1.89%: 中级资格为72.4万人,比去年增长了7.27%: 高级资格为 ...

  8. [乐意黎原创] 优盘硬盘等标称的16G, 32G, 64G, 128G, 256G内存容量,实际有多大?

    不时有朋友问乐意黎,说买的手机内存, 优盘, 硬盘什么的存在虚标, 跟他们解释了半天,是换算的问题.结果他们还是不太懂. 没办法,哎, 有必要进行一次科普了. 本文地址:http://blog.csd ...

  9. [乐意黎原创] 红米1刷MIUI 6 系统

    本人[乐意黎]于2014年1月左右买的红米1. 至今使用己有快一年三个月的时间,由于安装的程序和东西太多,总感觉原有的MIUI 5用起来太卡.体验过别人的小米NOTEbook手机上的MIUI 6 系统 ...

  10. C语言一定要有函数声明吗,1 什么是C语言的隐式函数声明在C语言中,函数在调用前不一定非要声明。如果没有声明,那么编译器会自动按照一种隐式声明的规则,为调用函数的C代码产生汇编代码。下...

    1 什么是C语言的隐式函数声明 在C语言中,函数在调用前不一定非要声明.如果没有声明,那么编译器会自动按照一种隐式声明的规则,为调用函数的C代码产生汇编代码.下面是一个例子: int main(int ...

最新文章

  1. 测试Robotium
  2. elasticsearch实战三部曲之三:搜索操作
  3. Kibana linux下安装
  4. PS教程第二十课:有了选区就有了界限
  5. flowable实战(四)flowable任务实例管理接口
  6. excel 单元格名称 java_Java 创建、编辑、删除Excel命名区域
  7. UVA10110 Light, more light【数学】
  8. hive执行更新和删除操作
  9. NEMA-0183(GPGGA,GPRMC,GPGSA,GPGSV,GPVTG)详解
  10. Bounds(包围盒)详解-【AABB包围盒、Sphere包围球、OBB方向包围盒、FDH固定方向凸包】
  11. linux如何卸载金山安全终端,卸载和释放-文档中心-金山云
  12. 并行是什么意思?与并发的区别是什么?
  13. 又来神器推荐嘞xshell与winSCP
  14. ElasticSearch 技术分析与实战 读后感
  15. 解决方案(二)— 将 http://apache.org/xml/features/disallow-doctype-decl 设置为“true”时, 不允许使用 DOCTYPE
  16. win7 查看网络计算机和设备,WIN7 网络发现已关闭 网络计算机和设备不可见
  17. 转载:数学工具常见问题集
  18. unity3d Daikon GUI 图片查看器 Demo 说明
  19. Apifox 测试工具
  20. C++语言程序设计第五版 - 郑莉(第二章课后习题)

热门文章

  1. java中Joiner的使用笔记
  2. STM32入门指南(0)—配置开发环境
  3. 金士顿服务器内存条怎么看型号,区分内存条型号的方法
  4. 笔记本如何不按Fn键就能实现F键的功能
  5. 群晖套件中心没有docker_群晖中通过docker安装huginn
  6. [good]使用Arduino操控RF 433Mhz射频发送器和接收器
  7. 华为手机USB连不上电脑的解决方法
  8. 路由器ipv4和ipv6转发原理
  9. 9011,9012,9013,9014,8050,8550 三极管的区别
  10. 信息安全概论———网络安全协议