Fork me on GitHub
随笔 - 87  文章 - 0  评论 - 308  阅读 - 42万

javascript中的函数式声明与变量式声明

观察下面两段代码,试写出hello('word');的运行结果:

复制代码
// 变量式声明
function hello(msg){
   alert(msg);
   var msg = function(){};
   alert(msg);
}

//函数式声明
function hello(msg){
   alert(msg);
   function msg (){};
   alert(msg);
}
复制代码

对于变量式声明,首先弹出word,然后弹出function,而函数式声明,则两次都是弹出function.这是为什么呢?

 

一: 函数式声明

复制代码
function hello(msg){
   alert(msg); //放在最前面的位置打印msg,是function
   function msg(){
      //这个msg是函数式声明,它会贯穿于整个fun函数的作用域
      //也就是说,只要fun一旦调用,甚至只要是进入语法分析阶段
      //那么msg函数就会首先解析,你可以把它想象成它是在fun函数
      //内的第一个变量。有的书上称这种现象为声明被提前或提升。
   }
   alert(msg);//放在最末尾的位置打印msg,也是function
  // 说明函数式声明在hello作用域内部是贯穿的
}

hello('xxx');
msg();// ReferenceError: msg is not defined
//说明函数式声明的msg也只是存在于hello函数内
复制代码

 

二:变量式声明

复制代码
function hello(msg){
 alert(abc); // 此时为undefined
  alert(msg); // 此时为形式参数msg的值
   var abc = function(){
    //这种是变量式声明,它在fun函数内的位置是固定的,也就是说
    // var abc之前,abc的值在fun内是undefined
    // var abc之后,abc才是它声明的值
    // 这种方式你可以理解成在fun函数的第一行写了一个var abc;
    // 也正因为如此,fun内声明的变量,会切断同名外部变量的引用;
    // 不论在hello作用域之外,abc的值是多少,在hello内部,在var abc之前,始终是undefined
    // 这是面试官最喜欢光顾的地方之一
   }

   alert(abc); // 此时才是function

// 这里把abc换成msg,道理也是一样的。对于hello内部来说,它的形参,就相当于是hello内部的局部变量。
// 这里有意用abc来替换msg,其实是为了简化问题,减少干扰项。既然是都hello内的局域变量,那么在声明之前
// 它的值为undefined也就是理所当然的事了。这里唯一有个要注意的地方就是,形参的声明,出现在所有局部变量之前。
// 后面对局部变量进行重复声明,系统会直接无视重复的声明过程,但是声明同时有赋值的话除外。
}
复制代码

 

   总结一点:函数式声明会上升到所属作用域的最前面, 变量式声明则不会.
 
   最后补充一点:
var abc = function(){};
   实际上是abc保存了一个无名函数的引用;本质上abc是一个变量.
   而 function abc(){} 是一个有名函数;本质上abc是函数;
 
  如果你喜欢,你可以用多个变量保存同一个函数的引用:
  
var xxx = abc; var bbb = abc;

引用可以无数,但是真身始终唯一。

   // xxx = null,bbb=null之后,abc该干嘛干嘛,而 var abc = function(){}; abc = null之后你就彻底的失去了有关abc的一切。
   abc从此石沉大海,从江湖上隐姓埋名,销声匿迹.......
 
  虽然两者在功能上是等价的,但是呢,我个人还是蛮倾向于把子函数, 人为的写在前面,这是为了避免压缩合并时,造成各种意外的结果。
  如果不是通用方法,我习惯用变量式声明,当然,这只是个人习惯。
 
对于函数式声明,它在整个作用域内可见,有的书上说是声明提升,有的说是声明提前。把这种现象取一个什么名头,不是那么重要了。
最后还要强调一点:命名函数表达式的名字只在该函数的作用域内部有效。也就是说,在hello函数内,无论用哪种方式声明msg这个函数,那么出了hello函数,都是不存在的。
posted on   bjtqti  阅读(1266)  评论(3编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示