Javascript Function无处不在,而且功能强大!通过Javascript函数可以让JS具有面向对象的一些特征,实现封装、继承等,也可以让代码得到复用。但事物都有两面性,Javascript函数有的时候也比较“任性”,你如果不了解它的“性情”,它很可能给你制造出一些意想不到的麻烦(bugs)出来。

  Javascript Function有两种类型:

  1)函数声明(Function Declaration);

    // 函数声明
function funDeclaration(type){
return type==="Declaration";
}

  2)函数表达式(Function Expression)。

    // 函数表达式
var funExpression = function(type){
return type==="Expression";
}

  上面的代码看起来很类似,感觉也没什么太大差别。但实际上,Javascript函数上的一个“陷阱”就体现在Javascript两种类型的函数定义上。下面看两段代码(分别标记为代码1段和代码2段):

1     funDeclaration("Declaration");//=> true
2 function funDeclaration(type){
3 return type==="Declaration";
4 }
1     funExpression("Expression");//=>error
2 var funExpression = function(type){
3 return type==="Expression";
4 }
  用函数声明创建的函数funDeclaration可以在funDeclaration定义之前就进行调用;而用函数表达式创建的funExpression函数不能在funExpression被赋值之前进行调用。
为什么会这样呢?!这就要理解Javascript Function两种类型的区别:用函数声明创建的函数可以在函数解析后调用(解析时进行等逻辑处理);而用函数表达式创建的函数是在运行时进行赋值,且要等到表达式赋值完成后才能调用。
这个区别看似微小,但在某些情况下确实是一个难以发现的陷阱。出现这个陷阱的本质原因体现在这两种类型在Javascript function hoisting(函数提升)和运行时机(解析时/运行时)上的差异。
关于变量提升https://www.cnblogs.com/gaoht/p/10404911.html
上面两段代码的函数提升可示意为下图:

代码1段JS函数等同于:
    function funDeclaration(type){
return type==="Declaration";
}
funDeclaration("Declaration");//=> true

代码2段JS函数等同于:
    var funExpression;
funExpression("Expression");//==>error
funExpression = function(type){
return type==="Expression";
}

  上述代码在运行时,只定义了funExpression变量,但值为undefined。因此不能在undefined上进行函数调用。此时funExpression赋值语句还没执行到。为了进一步加深JS函数两种类型的区别,下面给出一个更具迷惑性的示例,请看下面的代码(代码段4):

var sayHello;
console.log(typeof(sayHey)); //=>function
console.log(typeof(sayHo)); //=>undefined function sayHey() {
console.log("sayHey");
}
sayHello = function sayHo() {
console.log("sayHello");
} function sayHey() {
console.log("sayHey2");
}
sayHello = function sayHo() {
console.log("sayHello2");
} sayHey(); // => sayHey2
sayHello(); // => sayHello
分析:sayHey是用函数声明创建的,在JS解析时JS编译器将函数定义进行了函数提升,也就是说,在解析JS代码的时候,JS编译器(条件判断不形成新的作用域,两个sayHey函数定义都被提升到条件判断之外)检测到作用域内有两个同名的sayHey定义,第一个定义先被提升,第二个定义接着被提升(第二个定义在第一个定义之下),
第二个定义覆盖了第一个sayHey定义,所以sayHey()输出sayHey2;而sayHello是用函数表达式创建的,其表达式的内容是在JS运行时(不是解析时)才能确定(这里条件判断就起到作用了),
所以sayHello表达式执行了第一个函数定义并赋值,则sayHello()输出sayHello。

  代码段4的代码实际上等同于下面的代码(代码段5):

var sayHello;

function sayHey() {
console.log("sayHey");
} function sayHey() {
console.log("sayHey2");
}
console.log(typeof(sayHey)); //=>function
console.log(typeof(sayHo)); //=>undefined //hoisting...
sayHello = function sayHo() {
console.log("sayHello");
} //hoisting...
sayHello = function sayHo() {
console.log("sayHello2");
} sayHey(); // => sayHey2
sayHello(); // => sayHello2 并非是 sayHello

  总结

  Javascript 中函数声明和函数表达式是存在区别的,函数声明在JS解析时进行函数提升,因此在同一个作用域内,不管函数声明在哪里定义,该函数都可以进行调用。而函数表达式的值是在JS运行时确定,并且在表达式赋值完成后,该函数才能调用。这个微小的区别,可能会导致JS代码出现意想不到的bug,让你陷入莫名的陷阱中。

  最后附

  上图为sayHello函数执行的主要步骤示意图。

上图为sayHey函数执行主要步骤的示意图。若对闭包感兴趣,可以看另外一篇博文https://www.cnblogs.com/gaoht/p/10430853.html

js函数声明和函数表达式的区别的更多相关文章

  1. js学习之函数声明与函数表达式区别[原创]

    作为一名js初学者,与大家分享下.Javascript中有函数声明提升的功能,会优先编译函数声明部分.比如, ff(); function ff(){ alert("hello world. ...

  2. JS中的函数声明和函数表达式的区别,即function(){}和var function(){},以及变量提升、作用域和作用域链

    一.前言 Uncaught TypeError: ... is not a function function max(){}表示函数声明,可以放在代码的任何位置,也可以在任何地方成功调用: var ...

  3. JavaScript(js)函数声明与函数表达式的区别

    在JavaScript中,函数是经常用到的,在实际开发的时候,我想很多人都没有太在意函数的声明与函数表达式的区别,但是呢,这种细节的东西对于学好js是非常重要的. 函数声明与函数表达式用代码写出来是这 ...

  4. Js中函数声明和函数表达式的区别

    先看以下几段烧脑的代码: f();//=>? var f = function () { console.log("var"); } function f() { conso ...

  5. js 函数声明和函数表达式的区别

    javascript中声明函数的方法有两种:函数声明和函数表达式. 区别如下: 1).以函数声明的方法定义的函数,函数名是必须的,而函数表达式的函数名是可选的. 2).以函数声明的方法定义的函数,函数 ...

  6. JS的一些总结(函数声明和函数表达式的区别,函数中的this指向的问题,函数不同的调用方式,函数也是对象,数组中的函数调用)

    一.函数声明和函数表达式的区别: 函数声明放在if——else语句中,在IE8中会出现问题 函数表达式则不会 <script> if(true){ function f1(){ conso ...

  7. js中的函数声明和函数表达式的区别

    目录 一.声明与表达式的格式 1.1 声明式的格式: 1.2 表达式的格式: 二.区别 2.1 函数表达式可以直接在后面加括号执行,而函数声明不可以. 2.2 函数表达式可以被提前解析出来 2.3 命 ...

  8. JS高级---函数声明和函数表达式的区别

    函数声明和函数表达式的区别 多用函数表达式 var ff=function(){}; //函数声明 // // if(true){ // function f1() { // console.log( ...

  9. 【JS】函数提升变量提升以及函数声明和函数表达式的区别

    今天看js的变量提升问题,里面提到了函数提升.然后发现自己之前一直把函数声明和函数表达式弄错,导致函数提升出错 一.变量提升 console.log(a) var a=100 //undefined ...

随机推荐

  1. Spring Cloud使用样例

    Spring Cloud Demo 项目地址:https://github.com/hackyoMa/spring-cloud-demo 组件 基于Spring Boot 2.0.4.Spring C ...

  2. java8 按条件过滤集合

    //黄色部分为过滤条件list.stream().filter(user-> user.getId() > 5 && "1组".equals(user. ...

  3. linux内存 free命令 buffer cache作用

    free命令用于查看linux内存使用情况 #free shared:用于进程之间相互共享数据. Used:已使用内存. total:内存总量. free:未使用的内存. available:开启一个 ...

  4. 2.12 for循环

    for循环 像while循环一样,for可以完成循环的功能. 在Python中 for循环可以遍历任何序列的项目,如一个列表或者一个字符串等. for循环的格式 for 临时变量 in 列表或者字符串 ...

  5. js中的简单数据类型和复杂数据类型的存储

    基本类型存储的是值而复杂数据类型也叫引用类型存储的是对象的地址如0x00001而在栈中存的是变量数值和函数参数 堆中存的是对象和数组 堆栈空间分配 栈(操作系统):由操作系统自动分配释放 ,存放函数的 ...

  6. Wndows下Apache+php+Mysql环境的搭建及其涉及的知识(转)

    一.安装Apache 1. 在网上搜索以下3个文件,以及找一个地方新建一个文件夹 好吧,这里有下载链接:http://pan.baidu.com/s/1hr9IdSS 文件夹内有:apache,mys ...

  7. DeepLearning.ai学习笔记(五)序列模型 -- week1 循环序列模型

    一.为什么选择序列模型 序列模型可以用于很多领域,如语音识别,撰写文章等等.总之很多优点... 二.数学符号 为了后面方便说明,先将会用到的数学符号进行介绍. 以下图为例,假如我们需要定位一句话中人名 ...

  8. python加密

    ""#line:4 __all__ =[]#line:6 class OO0O0O000O0O0O000 :#line:8 ""#line:9 def __in ...

  9. Spring-boot 国际化

    在application.properties文件中配置 spring.message.basename=i18n.login 页面使用 th:text="#{login.tip}" ...

  10. 《剑指offer》字符串的排列

    本题来自<剑指offer> 反转链表 题目: 思路: C++ Code: Python Code: 总结: