一、前言

  Uncaught TypeError: ... is not a function

  function max(){}表示函数声明,可以放在代码的任何位置,也可以在任何地方成功调用;

  var max  = function(){};表示函数表达式,即将一个匿名函数赋值给一个变量,实现通过变量来调用这个匿名函数,但它需要在声明过后才能进行调用,如果调用在声明之前就会报如上红色字体的错误。而这在函数声明中不会出现这样的错误。

二、正文

(一)、代码示例

  1. //函数表达式
  2. myFunc();//此处调用会报错,即 Uncaught TypeError: myFunc is not a function
  3.  
  4. var myFunc = function(){
  5. alert("函数表达式")
  6. }
  7. myFunc();//此处调用正确
  8. =======================================================================
  9. //函数声明
  10. otherFunc();//对于函数声明,此处调用可以使用
  11.  
  12. var otherFunc = function(){
  13. alert("函数声明")
  14. }
  15. otherFunc();//此处调用也可以

可见对于函数表达式的使用,不可以提前进行调用,而函数声明却可以,为什么呢?

(二)、原因分析===JS作用域和声明提前,以及作用域和作用域链

1. JS的作用域:

  变量有全局变量和局部变量之分,两者的区别在于作用域的不同;

  •   全局作用域:针对于全局变量来说,全局变量在整个上下文都有效,只是在没有赋值之前调用,会输出undefined;
  •   函数作用域:是针对局部变量来说的,在函数中定义的变量在函数外不能获取;
  •   块级作用域:概念“{}”中间的部分都是块级作用域ex:for while if ,js中没有块级作用域,但是可以用闭包实现类似功能。
  1. alert(c);//输出undefind
  2.  
  3. // alert(d);报错 Uncaught ReferenceError: d is not defined
  4.  
  5. // alert(b);报错 Uncaught ReferenceError: b is not defined
  6.  
  7. var c=3;
  8.  
  9. function test(){
  10. var a=1;
  11. b=2; //没有var直接赋值的变量都属于全局变量
  12.  
  13. alert(c)//输出3,
  14. }
  15. // alert(b);报错 Uncaught ReferenceError: b is not defined
  16.  
  17. alert(c);//输出3
  18.  
  19. test();
  20.  
  21. // alert(a);报错 Uncaught ReferenceError: a is not defined
  22.  
  23. alert(b);//输出2,在test执行过后才能把b变为全局变量
  1. function test(){
  2. alert(a);//声明未赋值输出undefine
  3.  
  4. var a=1;
  5.  
  6. alert(a);//1
  7. }
  8. // alert(a);报错,外部获取不到
  9.  
  10. test();
  11.  
  12. //alert(a);报错,Uncaught ReferenceError: a is not defined

注意 :

  • 如果在函数中去掉var进行声明(如代码中的b),则变量就会从局部变量升级为全局变量。
  • 局部变量的优先级高于同名的全局变量 。如果在函数中声明一个局部变量同名,则全局变量就会被局部变量覆盖。

2. JS的变量提升:

  变量在声明之前就已经可用,因为浏览器在进行“预解析”时,对每个函数作用域中的所有变量和函数都会先提取出来,提前进行解析。

  我们称这种特性为声明提前,也就是预解析。

  1. //变量提前,会对var和function,即变量和函数进行提前解析
  2. console.log(a) //打印function a(){console.log("123")}
  3.  
  4. var a=1
  5.  
  6. function a(){console.log("123")}
  7.  
  8. var a=10
  9.  
  10. console.log(a)
  11.  
  12. //预解析的过程a=undefined, a=function a(){...}, a=undefined
  13. //预解析的结果是a=function a(){...}
  14.  
  15. //最终执行的结果是a=10,后面的覆盖前面的

几点说明:

  • 将变量声明提升,只提升变量,不提升所赋的值;
  • 将函数声明及函数内容提升,既提升函数声明,又提升函数内容,可以理解为将整个function内容提升;
  • 块内的变量声明和函数声明也会被提升,例如if语句。

三个重名冲突:

  • 遇到重名,预解析后只留下一个;
  • 如有重名变量和函数,留下函数,因为函数有内容;
  • 如有两个重名函数,后一个函数覆盖前一个函数。

3. JS的作用域链

  作用域:是一个函数在执行时期的执行环境

  作用域嵌套:嵌套内函数的执行会引用其“父函数”的作用域,例如B()和C()的执行会引用A()的作用域;

  作用域链:像这种函数作用域的嵌套就组成了所谓的函数作用域链;

       当在自身作用域内找不到该变量的时候,会沿着作用域链逐步向上查找,若在全局作用域内部仍找不到该变量,则会抛出异常。

  1. //name="123";
  2. function A(){
  3. var name="456";
  4. function B(){
  5. var name="789";
  6. console.log(name); //首先在函数内查找name,查找到所以结果是“789”
  7. }
  8. function C(){
  9. console.log(name); //首先在函数内没有找到,向作用域链的上一级查找,找到了,结果是“456”
  10. }
  11. s();
  12. ss();
  13. }
  14. t();
  15. console.log(name); //此处再次进行查找,当前作用域内没有,整个链上都没有,结果就是未定义

三、总结

  函数声明和函数表达式相比,函数声明使用可以更加自由,可以放在随意的位置,因为它能够整体的变量提升;

  而函数表达式使用就相对没有那么自由了,调用必须在声明的后面,因为变量提前只是将表达式的变量提前,并没有将表达式的内容提前。

  

  作用域:Js是以函数范围作为基本的局部;

  • 全局作用域:针对于全局变量来说,全局变量在整个上下文都有效,只是在没有赋值之前调用,会输出undefined;
  • 函数作用域:是针对局部变量来说的,在函数中定义的变量在函数外不能获取;

  

  变量提升:是相对于作用域来说的,在每个作用域中,无论全局还是函数作用域,声明的变量和函数,都能够变量提升,也就是可以在声明之前进行使用(调用)。

  作用域链:函数的嵌套,使得子函数的执行会引用父函数的作用域,像这种函数作用域的嵌套就组成了所谓的函数作用域链;

  当在自身作用域内找不到该变量的时候,会沿着作用域链逐步向上查找,若在全局作用域内部仍找不到该变量,则会抛出异常。

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

  1. JS中函数声明与函数表达式的不同

    Js中的函数声明是指下面的形式: function functionName(){   } 这样的方式来声明一个函数,而函数表达式则是类似表达式那样来声明一个函数,如 var functionName ...

  2. JS中函数声明与函数表达式的异同

    相同点 注:函数声明和函数表达式的相同点包括但不限于以下几点 函数是一个值,所以和其他值一样,函数也可以进行被输出.被赋值.作为参数传给其他函数等相关操作,不管函数是以什么方式被定义的,当然和其他值的 ...

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

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

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

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

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

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

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

    Javascript Function无处不在,而且功能强大!通过Javascript函数可以让JS具有面向对象的一些特征,实现封装.继承等,也可以让代码得到复用.但事物都有两面性,Javascrip ...

  7. 转载 js函数声明和函数表达式

    在js中函数有两种表达方式.1 函数声明 2 函数表达式 函数声明 function sayname(){ alert("li lei"); } 函数表达式 var sayname ...

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

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

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

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

随机推荐

  1. Oracle12c之 CDB数据库中数据字典架构

    数据字典就是元数据的集合,比如创建的表,列,约束,触发器等等这些都是元数据,需要保存到数据库中.除此之外,Oracle自身的一些数据库对象,如目录,PL/SQL代码等等这些都是元数据,都需要存放在数据 ...

  2. 求助OPC Opc.IDiscovery m_discovery = new OpcCom.ServerEnumerator();

    各位大哥们,大家好,在此请教各位一个问题,谢谢大家.我在vs2010中引用了OpcNetApi.dll和OpcNetCom.dll并且加入了using Opc;using Opc.Da;using O ...

  3. Asp.net中的web.config配置文件(转)

    最近开始学习.NET的开发,首先碰到的就是web.config的配置问题,把网上大虾的资料转发记录一下,以备不时之需. 原贴路径如下:http://blog.csdn.net/hbqhdlc/arti ...

  4. couchdb的使用例子

    couchdb安装 sudo apt-get install erlang sudo apt-get install libmozjs185-dev libicu-dev 下载源码,编译安装 启动以后 ...

  5. 谈谈对zynq的浅显理解

    zynq并不能说是一个嵌入arm核的FPGA.从它的启动过程就可以发现,绝对是arm主导的,所以称它为以高性能FPGA为外设的双核arm或许更为合适.以下是优势: 第一个:开发环境的大集成.从hls到 ...

  6. 后台判断ajax请求的请求后字段

    headers设置:X-Requested-With:XMLHttpRequest    后台我就是根据这个来判断的

  7. 同步机制之--java之CountDownLatch闭锁

    CountDownLatch闭锁 1.类介绍 一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待.用给定的计数初始化 CountDownLatch.CountDown ...

  8. 杂项:HTML5-2/3-新元素

    ylbtech-杂项:HTML5-2/3-新元素 自1999年以后HTML 4.01 已经改变了很多,今天,在HTML 4.01中的几个已经被废弃,这些元素在HTML5中已经被删除或重新定义. 为了更 ...

  9. AngularJS.js: 杂项

    ylbtech-AngularJS.js: 杂项 AngularJS诞生于2009年,由Misko Hevery 等人创建,后为Google所收购.是一款优秀的前端JS框架,已经被用于Google的多 ...

  10. ConditionObject分析

      ConditionObject是AQS中的内部类,提供了条件锁的同步实现,实现了Condition接口,并且实现了其中的await(),signal(),signalALL()等方法. Condi ...