JavaScript进阶(二十三):立即执行函数(匿名函数)( ( ) { } ( ) )含义解析

文章目录

    • 一、前言
    • 二、立即执行函数
      • 2.1 立即执行函数使用的场景
    • 三、拓展阅读

一、前言

前端项目改造过程中,引入的工具类实现如下:

var tensquared=(function(x) {return x*x;
}(10));  

拆解以上语句如下:

  1. var tensquared = xx; 这是赋值语句;

  2. function (x){ return x*x; } 这是一个匿名函数;所谓的匿名函数是指它没有自己的名字,既不是function name(){};拥有一个函数名,也不是var name = function(){};将函数赋给一个变量地址用于日后的调用;

为什么会有这样的函数呢,因为有时候只是临时地一次性地使用一个函数,用过了这个函数也就再没用了,那么这个时候就用到了匿名函数(当然,并不一定说只有一次性的才会用到匿名函数,还有其它的情况,不一一举例了。)

  1. 函数() 这样的语句我们都知道是让一个函数运行,而括号中的值表示传值,比如:
function name(arg){ alert(arg); };
name('yes');

那么,程序执行到name();这个语句的时候,会将’yes’这个字符串传递到函数name中去,并执行name函数;

上面的函数我们再来理解一下:
function(x){return x*x;}是一个函数,然后直接在它后面加上个括号,是不是表示直接运行这个匿名函数呢:

function(x) {return x*x;}(10)

这一步等价于下面的方法:

function name(x){return x*x;}
name(10);

再加上赋值:

var tensquared = function(x) {return x*x;}(10);

是不是与下面这一系列的代码起到的效果一样呢:

function name(x){return x*x}
var tensquared = name(x);

应用下面这种实现方式之后,name()函数以后还可以通过name(值);这样的方式再一次去调用,因为有函数名,就可以用这个方法调用到它;

var tensquared=function(x) {return x*x;}(10)这样的方式,是当时就执行了,然后将执行的结果赋值给了它前面的变量tensquared,以后想再调用return x*x所在的函数,却没办法了,因为它没名字,运行后就找不到了;

最后说说外面的括号,这个括号其实是可有可无的,而且这个括号的用法与人们常用的另一种用法有所偏差,因为括号括在最外围,已经失去了它的意义,其实应该是这样的:

var tensquared=(function(x) {return x*x;})(10);

只将匿名函数本体给括了起来,因为有时候function函数体很长,那么加一个括号告诉程序,这是一个完整的整体,其实这一步就算这样用,也是可有可无的。

再说说这种用法的意义:

像这种用法,大多数时候就是用来获取到一个值,而这个值却是需要一系列的计算后才能得到的,而这个计算的过程,只需用到一次,不需要再用第二次了,这时候,这种语句结构就有用了。

例如获取用户在使用浏览器类型:

var browser = function(){if(IE浏览器) return 'IE';else if(是chrome浏览器) return 'CH';else if(是Firefox浏览器) return 'FF';
}();

后面如果再想知道用户的浏览器名称,只要调用browser这个变量,看看返回的字符串就可以了。

二、立即执行函数

阅读源码过程中,经常看到一些大牛的JS源码会在function前面加语句结束符;

;(function(arg){//some js code in here
})(param);

;function($,undefined) 是什么用处 ?

其实它就是创建了一个匿名函数function(arg){ //some js code in here },然后再执行且只执行该函数一次,param为实参。

最前面加;是为了防止其他语句的影响,因此语句结束符;可有可无。如:

new
(function() {this.prop = 4;
}) ().prop;

上面将匿名函数用作构造函数,然后实例化并取出prop属性值。

在前面加分号可以有以下几种用途:

  1. 防止多文件集成成一个文件后,高压缩出现语法错误。

  2. 这是一个匿名函数,一般js库都采用这种自执行的匿名函数来保护内部变量 (function(){})()

  3. 因为undefinedwindow的属性,声明为局部变量之后,在函数中如果再有变量与undefined作比较的话,程序就可以不用搜索undefinedwindow,可以提高程序性能。

立即执行函数👉🏻:声明一个函数,并马上调用这个匿名函数就叫做立即执行函数;即立即执行函数是定义函数以后立即执行该函数。

定义好函数之后,立即调用该函数,这时不能在函数的定义后面直接加圆括号,会产生语法错误。

//这是错误的
function fn(){}()

这是因为:function 这个关键字,既可以当做语句,也可以当做表达式
比如:

//语句
function fn() {};
//表达式
var fn = function (){};

为了避免解析上的歧义,JS引擎规定,如果function出现在行首,一律解析成语句。

因此JS引擎看到行首是function关键字以后,认为这一段都是函数定义,不应该以原括号结尾,所以就报错了。

解决方法就是不要让function出现在行首,让JS引擎将其理解为一个表达式。最简单的处理就是将其放在一个圆括号里,比如下边:

//立即执行函数的两种写法//第一种:用括号把整个函数定义和调用包裹起来
(function(){//function body
}())//第二种:用括号把函数定义包裹起来,后面再加括号
(function (){//function body
})()

上边的两种写法,就是立即执行函数的两种写法,都是以圆括号开头,JS引擎会认为后面跟的是表达式,而不是一个函数定义语句,所以就避免了错误,这就叫做"立即调用的函数表达式"

在这里插入图片描述

立即执行函数一般也写成匿名函数,匿名函数写法为function(){/…/},所谓匿名函数,就是使用function关键字声明一个函数,但未给函数命名,倘若需要传值,直接将参数写到括号内即可。

将它赋予一个变量则创建函数表达式,赋予一个事件则成为事件处理程序等。但是需要注意的是匿名函数不能单独使用,否则会js语法报错,至少要用()包裹起来。

了解了立即函数的原理,就可以再扩展出其他的写法:

(function foo(){console.log("Hello World!")}())//用括号把整个表达式包起来,正常执行
(function foo(){console.log("Hello World!")})()//用括号把函数包起来,正常执行
!function foo(){console.log("Hello World!")}()//使用!,求反,这里只想通过语法检查。
+function foo(){console.log("Hello World!")}()//使用+,正常执行
-function foo(){console.log("Hello World!")}()//使用-,正常执行
~function foo(){console.log("Hello World!")}()//使用~,正常执行
void function foo(){console.log("Hello World!")}()//使用void,正常执行
new function foo(){console.log("Hello World!")}()//使用new,正常执行

立即执行函数主要有以下特点:

  1. 不必为函数命名,避免污染全局变量。
  2. 立即执行函数内部形成一个独立的作用域,可以封装一些外部无法读取的私有变量,这个作用域里面的变量,外面访问不到,这样就可以避免变量污染。
  3. 封装变量。
  4. 闭包和私有数据。

2.1 立即执行函数使用的场景

  1. 代码逻辑在页面加载完成之后,不得不执行一些设置工作,比如时间处理器,创建对象等等。
  2. 所有的这些工作只需要执行一次,比如只需要显示一个时间。
  3. 但是这些代码也需要一些临时的变量,但是初始化过程结束之后,就再也不会被用到,如果将这些变量作为全局变量,不是一个好的注意,可以用立即执行函数——去将所有的代码包裹在它的局部作用域中,不会让任何变量泄露成全局变量,如下代码:

在这里插入图片描述

比如上面的代码,如果没有被包裹在立即执行函数中,那么临时变量todaydom,days,today,year,month,date,day,msg都将成为全局变量(初始化代码遗留的产物)。用立即执行函数之后,这些变量都不会在全局变量中存在,以后也不会其他地方使用,有效的避免了污染全局变量。

总结👇🏻:立即执行函数会形成一个单独的作用域,可以封装一些临时变量或者局部变量,避免污染全局变量。

三、拓展阅读

  • 《JavaScript进阶》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/100565.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML5+CSS3+移动web 前端开发入门笔记(二)HTML标签详解

HTML标签&#xff1a;排版标签 排版标签用于对网页内容进行布局和样式的调整。下面是对常见排版标签的详细介绍&#xff1a; <h1>: 定义一级标题&#xff0c;通常用于标题栏或页面主要内容的标题。<p>: 定义段落&#xff0c;用于将文字分段展示&#xff0c;段落之…

Jmeter 链接MySQL测试

1.环境部署 1.1官网下载MySQL Connector https://dev.mysql.com/downloads/connector/j/ 1.2 解压后&#xff0c;将jar放到jmeter/lib目录下 1.3 在测试计划中添加引用 2.脚本设置 2.1设置JDBC Connection Configuration 先添加一个setUp线程中&#xff0c;在setUp中添加“…

2023年台州市第三届网络安全技能大赛(MISC)—Black Mamba

前言&#xff1a;当时比赛没有做出来现在来复现一下 就当记录一下&#xff08;这个思路没想到&#xff09; Black Mamba&#xff1a; 一张图片 常规得分离&#xff0c;属性&#xff0c;LSB&#xff0c;盲水印等都尝试过 无果&#xff01; 考点&#xff1a;异或解密&#xff0…

计算机算法分析与设计(8)---图像压缩动态规划算法(含C++代码)

文章目录 一、知识概述1.1 问题描述1.2 算法思想1.3 算法设计1.4 例题分析 二、代码 一、知识概述 1.1 问题描述 1. 一幅图像的由很多个像素点构成&#xff0c;像素点越多分辨率越高&#xff0c;像素的灰度值范围为0~255&#xff0c;也就是需要8bit来存储一个像素的灰度值信息…

C# 为什么要限制静态方法的使用

前言 在工作了一年多之后&#xff0c;我发现静态方法的耦合问题实在是头疼。如果可以尽量不要使用静态方法存储数据&#xff0c;如果要存储全局数据就把数据放在最顶层的主函数里面。 静态方法问题 耦合问题&#xff0c;不要用静态方法存储数据 我这里有两个静态方法&#…

已知文档被分成几个区块,一些行被改动,现在要求把有改动的区块找出来应该怎么做

要找出文档中被修改的区块&#xff0c;您可以使用文本比对&#xff08;text diff&#xff09;算法来比较原始文档和修改后的文档&#xff0c;并找到差异。这可以通过编程来完成&#xff0c;以下是一些常见的步骤&#xff1a; 将文档分成区块&#xff1a; 首先&#xff0c;您需要…

Java线程的基本操作(设置和获取、sleep、interrupt、join、yield、daemon、线程状态总结)

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开兴好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;…

【每日一练】勾股定理困难版

目录 题目官方给的解题思路源代码附最大公因数辗转相除法更相减损术 所有因数参考文献 题目 给定斜边z的值&#xff0c;求所有直角边x和y的组合数&#xff08;x、y和z都是正整数&#xff09;。 仅有一行输入&#xff0c;即斜边z的值&#xff08;z是正整数&#xff0c;且z<1…

nginx配置实例-负载均衡

1 实现效果&#xff1a; 浏览器访问nginx&#xff0c;输入访问nginx地址&#xff0c;然后负载均衡到tomcat8080和8002端口中 2 准备工作&#xff1a; 1&#xff09;准备两台tomcat容器&#xff0c;一台8080&#xff0c;一台8081 2&#xff09;在两台tomcat里面的webapps目录…

提升企业管理效率!金蝶软件配置自定义域名,快速实现公网远程访问

文章目录 前言1. 保留自定义域名2. 域名解析3. 配置自定义域名4. 关于服务器选择以及域名备案的说明4.1 关于服务器地区的选择&#xff1a;4.2 关于自定义域名备案&#xff1a;4.3 关于域名过白名单&#xff1a; 前言 上篇文章我们讲过如何安装金蝶云星空&#xff0c;实现异地…

rust文件读写

std::fs模块提供了结构体File&#xff0c;它表示一个文件。 一、打开文件 结构体File提供了open()函数 open()以只读模式打开文件&#xff0c;如果文件不存在&#xff0c;则会抛出一个错误。如果文件不可读&#xff0c;那么也会抛出一个错误。 范例 fn main() {let file s…

云计算引领数字化时代

一、云计算的定义和演进 云计算是一种通过互联网将计算资源&#xff08;例如存储、处理能力和软件等&#xff09;提供给用户的方式。这种分布式的计算模式&#xff0c;使得用户无需购买昂贵的硬件设备&#xff0c;也不需要关注底层的技术细节&#xff0c;只需通过互联网就能获…

wpf webBrowser控件 常用的函数和内存泄漏问题

介绍 WebBrowsers可以让我们在窗体中进行导航网页。 WebBrowser控件内部使用ie的引擎&#xff0c;因此使用WebBrowser我们必须安装ie浏览器&#xff08;windows默认安装的&#xff09;。 使用 直接在xmal中使用webBrowser控件 <WebBrowser x:Name"WebBrowser1"…

【C++】List -- 详解

一、list的介绍及使用 https://cplusplus.com/reference/list/list/?kwlist list 是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。 list 的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&…

PCA和SVD数据降维

PCA&#xff08;Principal Component Analysis&#xff09; 是一种常见的数据分析方式&#xff0c;常用于高维数据的降维&#xff0c;可用于提取数据的主要特征分量。 最大可分性 基向量乘原始矩阵会将矩阵映射到这个基向量空间中&#xff0c;如果基的数量少于向量本身的维数…

SQLite事务处理

语法 BEGIN TRANSACTION; COMMIT TRANSACTION; &#xff08;或END TRANSACTION;&#xff09; ROLLBACK TRANSACTION; 事务处理 除了一些PRAGMA语句以外&#xff0c;其它访问数据库的语句会自动启动事务处理&#xff0c;并且在结束时自动提交。 通过上一节的命令可以手动控制…

c++ linux 配置

https://blog.csdn.net/zimuzi2019/article/details/106861692

数据产品读书笔记——认识数据产品经理

&#x1f33b;大家可能听说的更多是产品经理这个角色&#xff0c;对数据产品经理可能或多或少了解一些&#xff0c;但又不能准确的描述数据产品经理的主要职能和与其他产品的不同&#xff0c;因此通过读一些书来对数据产品经理有一个准确且全面的认知。 目录 1. 数据的产品分类…

安卓 kotlin-supportFragmentManager报红

如果你继承baseActivity 请查看 是不是继承 AppCompatActivity

sface人脸相似度检测

sface人脸相似度检测&#xff0c;基于OPENCV&#xff0c;人脸检测采用yunet&#xff0c;人脸识别采用sface&#xff0c;支持PYTHON/C开发&#xff0c;图片来自网络&#xff0c;侵权请联系本人立即删除 yunet人脸检测sface人脸识别&#xff0c;检测两张图片的人脸相似度