js的匿名函数_匿名函数

js的匿名函数_匿名函数1.函数的声明与函数表达式区别1.1函数的声明如下方法add就是函数声明的代码结构:functionadd(x,y){alert(x+y)}add(1,2)//弹窗显示:3关于函数声明,它最重要的一个特征就是函数声明提升,意思是执行代码之前先读取函数声明。不管函数声明写在前面,还是后面,都会出现函数声明的提升。如下代码可以正确执行:add(1,2…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

1. 函数的声明与函数表达式区别

1.1 函数的声明

如下方法 add 就是函数声明的代码结构:

function add(x,y){  
   alert(x+y) 
}  
add(1,2) //弹窗显示:3  

关于函数声明,它最重要的一个特征就是函数声明提升,意思是执行代码之前先读取函数声明。不管函数声明写在前面,还是后面,都会出现函数声明的提升。
如下代码可以正确执行:

add(1,2); //弹窗显示:3  
function add(x,y){  
    alert(x+y) 
}  

1.2 函数表达式

函数表达式中有几种不同的语法。最常见和最具代表性的一种如下所示:

var add = function(x,y){  
    alert(x+y) 
}
add(1,2) //弹窗显示:3

这种形式看起来好像是常规的变量赋值语句。但是函数表达式和函数声明的区别在于,函数表达式在使用前必须先赋值。所以这段代码执行的时候就会出错:

add(1,2) //无弹窗,报错: add is not a function  
var add = function(x,y){  
    alert(x+y)  
} 

造成这种现象是因为解析器在向执行环境中加载数据时,解析器会率先读取函数声明,并使其在执行任何代码前可用;至于函数表达式,则必须等到解析器执行到它的所在的的代码行,才会真正的被解析。函数表达式中,创建的函数叫做匿名函数,因为function关键字后面没有标识符。

1.3 区别

JS中常见的两种函数声明(statement)方式有这两种:

复制代码
// 函数表达式(function expression) 
var h = function() {
      // h
}

// 函数声明(function declaration) 
function h() {
      // h
}

先说两者的显著区别:

  • 第一种声明方式也就是var声明方式, 函数只有在var语句声明之后才能被调用

  • 第二种生命方式也就是function声明方式, 函数可以在function声明之前被调用

这是因为,

  • 对第一种情况, 函数表达式是在函数运行阶段才赋值给变量h

  • 对第二种情况, 函数表达式是在代码运行阶段之前, 也就是代码解析阶段才赋值给标识符h

为了证明这种说法可以看下面两个例子:

对应第一种情况,

var h = function () {
      // h
}

console.log(h)
    
h = function () {
      // h1
}

console的结果是

ƒ h() {
  // h
}

因为赋值发生在代码运行阶段, 代码自上而下运行console.log(h)所在位置只能获取它之前的赋值

对应第二种情况,

function h() {
      // h
}

console.log(h)
    
function h() {
      // h1
}

console的结果是

ƒ h() {
  // h1
}

因为赋值发生在代码解析阶段, 代码运行到console.log(h)时解析早已完成, 而解析的结果是后面那个函数h, 故会打印此结果

深入:

JS声明函数的三种方式:

  • 1.函数表达式: 即上面第一种方式, 这种方法使用function操作符创建函数, 表达式可以存储在变量或者对象属性里. 函数表达式往往被称为

匿名函数, 因为它没有名字. 证明这一点你可以 console.log(h.name); 可以看到打印为空 “”

  • 2.函数声明: 即上面第二种方式, 会声明一个具名函数, 且函数能在其所在作用域的任意位置被调用, 其创建的函数为具名函数, 证明这一

点你可以 console.log(h.name); 可以看到打印为 “h”. 可在后面的代码中将此函数通过函数名赋值给变量或者对象属性

  • 3.Function()构造器: 不推荐这种用法, 容易出问题

2. 匿名函数的调用方式

匿名函数,就是没有名字。

2.1 调用方式

还有一种匿名函数的调用方式是:使用()将匿名函数括起来,然后后面再加一对小括号(包含参数列表)。我们再看一下以下一个例子:

//表达式的调用
/*
const add = function (x, y){
    return x + y;
}
const sum = add(1, 2)

console.log(sum)
*/

//匿名函数式调用
//方式1
//这种方式尽量少用
const sum1 = function(x, y){
    return x + y;
}(1, 2);

//方式2
//推荐
const sum = (function(x, y){
    return x + y;
})(1, 2);
console.log(sum1);

//方式3
(new Function("x","y","return x+y"))(1,2)

javascript中,是没有块级作用域这种说法的,以上代码的这种方式就是模仿块级作用域(通常成为私有作用域),语法如下所示:

(function(){  
    //这里是块级作用域  
})();  

以上代码定义并立即调用了一个匿名函数。经函数声明包含在一对圆括号中,表示它实际上是一个函数表达式。而紧随其后的另一对圆括号会立即调用这个函数。然而要注意一点:

function(){  
      
}();  

上面的代码是错误的,因为Javascript将function关键字当作一个函数声明的开始,而函数声明后面不能加圆括号,如果你不显示告诉编译器,它会默认生成一个缺少名字的function,并且抛出一个语法错误,因为function声明需要一个名字。有趣的是,即便你为上面那个错误的代码加上一个名字,他也会提示语法错误,只不过和上面的原因不一样。提示为:Uncaught SyntaxError: Unexpected token ( 。

在一个表达式后面加上括号(),该表达式会立即执行,但是在一个语句后面加上括号(),是完全不一样的意思,只是分组操作符。

function foo(){
   alert('测试是否弹窗')
}() 
// SyntaxError: Unexpected token ) 
// 报错因为分组操作符需要包含表达式

function foo(){ 
    alert('测试是否弹窗')
}(1) 
// (1) => 等价于 1
// 相当于foo方法后面个跟了一个无关系的表达式子:(1)

所以上面代码要是想要得到想要的弹窗提示,就必须要实现赋值,如

a = function(){

alert(‘测试是否弹窗’)
}()
// 弹窗提示成功

“a=” 这个片段告诉了编译器这个是一个函数表达式,而不是函数的声明。因为函数表达式后面可以跟圆括号。

因此下面两段代码是等价的

var aa = function(x){  
    alert(x)  
}(5) //弹窗显示:5  
(function(x){
    alert(x)
})(5) //弹窗显示:5    

3.自执行匿名函数

自执行函数,即定义和调用合为一体。我们创建了一个匿名的函数,并立即执行它,由于外部无法引用它内部的变量,因此在执行完后很快就会被释放,关键是这种机制不会污染全局对象

下面我们来看下一些比较有趣的自执行函数表达方式:

// 下面2个括弧()都会立即执行  
(function () { /* code */ } ()) // 推荐使用这个  
(function () { /* code */ })() // 但是这个也是可以用的  
  
// 由于括弧()和JS的&&,异或,逗号等操作符是在函数表达式和函数声明上消除歧义的  
// 所以一旦解析器知道其中一个已经是表达式了,其它的也都默认为表达式了  
var i = function () { return 10; } ();  
true && function () { /* code */ } ();  
0, function () { /* code */ } ();  
  
// 如果你不在意返回值,或者不怕难以阅读
// 你甚至可以在function前面加一元操作符号  
!function () { /* code */ } ();  
~function () { /* code */ } ();  
-function () { /* code */ } ();  
+function () { /* code */ } ();  
  
// 还有一个情况,使用new关键字,也可以用,但我不确定它的效率  
// http://twitter.com/kuvos/status/18209252090847232  
new function () { /* code */ }  
new function () { /* code */ } () // 如果需要传递参数,只需要加上括弧()  

 

参考

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/186135.html原文链接:https://javaforall.net

(0)
上一篇 2022年10月4日 上午9:16
下一篇 2022年10月4日 上午9:16


相关推荐

  • 【iOS安全】App Store 应用爬取「建议收藏」

    【iOS安全】App Store 应用爬取「建议收藏」AppStore应用爬取

    2022年7月15日
    34
  • Python– lxml用法

    Python– lxml用法目录 lxml 库 lxml 安装可查看上一篇文章 Element 类 1 节点操作 2 属性操作 3 文本操作 4 文件解析与输出 5 ElementPath6 案例 尤其最后的一篇代码 nbsp nbsp lxml 库 lxml 安装可查看上一篇文章 python 的 HTML XML 的解析器 官方文档 nbsp http lxml de index html 功能 解析 HTML

    2026年3月18日
    1
  • 计算机办公软件的快捷方法,干货!计算机办公软件快捷键小合集

    计算机办公软件的快捷方法,干货!计算机办公软件快捷键小合集在当代科学技术迅速发展的时期 电脑已经成为我们每个人的生活工作必须技能 在我们平时的工作中 工作是量大 繁琐 压力大枯燥的 这个时候我们就需要利用一些电子科学技术 小技巧来让我们的工作变得轻松 变得迅速 小编觉得 只有我们员工的工作效率高了 然后老板才会重视我们 然后升职加薪就不在话下了 对吧 为了我们更好工资待遇 更好的生活质量 我们必须提升自身的技能 当然要提升我们自身的技能技巧 这是需要付出

    2026年3月20日
    2
  • 一文弄懂罗斯蒙特644温度变送器接线

    一文弄懂罗斯蒙特644温度变送器接线罗斯蒙特644温度变送器分为单输入644H和双输入644S两种,昌晖仪表在本文介绍温度变送器644接线,大家学习一起罗斯蒙特644温度变送器接线的注意事项。问题1:下图①位置这四个端子是干什么的?问题2:下图②位置这三个端子是干什么的?问题3:下图③位置这三个端子是干什么的?问题4:下图④位置这个插针是干什么的?问题5:下图⑤位置拨盘L和H位置代表什么?问题6:上图⑥位置这两个端子是干什么的?结…

    2022年6月21日
    78
  • iOS int 转 char

    iOS int 转 charcharsongID 100 NSLog c songID 输出 d 这样就强转了

    2026年3月26日
    1
  • docker部署redis哨兵集群_redis部署安装

    docker部署redis哨兵集群_redis部署安装Docker安装Docker部署redis在dockerhub上可以看到有redis的官方镜像不去网站,也可以通过如下命令查看有那些镜像可用Dockersearch命令dockersearchredis拉取redis镜像Dockerpull命令这里我们拉取官方的最新版本的镜像:dockerpullredis:latest查看本地镜像Dockerimages命令有redis和hello-world运行容器Dockerrun命令d

    2022年10月18日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号