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

news2024/10/6 20:25:50

文章目录

    • 一、前言
    • 二、立即执行函数
      • 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.coloradmin.cn/o/1076397.html

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

相关文章

Redis学习2——String数据类型的操作

Redis常用数据类型 String 数据结构 有点像动态分区按边界对齐。 基本操作 也可以一次设置多个 得到范围值 setrange和append的区别是宏观上看append是从尾部追加而setrange是从设置的起始位置开始的。 也可以在set时就对key设置过期时间, 最后一个是

九小场所安全隐患排查—线上隐患上报、整改

为进一步加强治安管理工作,严格落实安全责任,扎实筑牢“安全防火墙”,营造和谐、稳定、文明的社会环境。我们可借助凡尔码搭建九小场所安全码,实现消防安全监督管理,落实消防安全责任,形成九小场所网格化监…

5 款漏洞扫描工具:实用、强力、全面(含开源)

引言 漏洞扫描是一种安全检测行为,更是一类重要的网络安全技术,它能够有效提高网络的安全性,而且漏洞扫描属于主动的防范措施,可以很好地避免黑客攻击行为,做到防患于未然。那么好用的漏洞扫描工具有哪些? …

防止SQL注入攻击的综合解决方案

文章目录 摘要背景和危害性防御措施示例代码(Java)示例代码(PHP)示例MySQL命令示例代码(Python)示例代码(C#,使用Entity Framework) 进一步防御SQL注入攻击的措施使用ORM…

SpringCloud组件Ribbon的IRule的问题排查

最近很久没有写文章啦,刚好遇到了一个问题,其实问题也挺简单,但是还是得对源码有一定了解才能够发现。 最近在实现一个根据请求流量的标签,将请求转发到对应的节点,其实和俗称的灰度请求有点相似, 实现思…

Redis安装教程

官网地址 地址链接:传送门 安装步骤 这里有更多版本的选择 进去根据自己的需要选择版本,我这里用的7系列的稳定版。

软件企业找第三方软件测评机构做确认测试有什么优势?

软件确认测试是一个在软件开发过程中十分重要的环节。它确保了软件的功能符合预期,达到了用户的需求和期望。确认测试主要验证软件的功能、性能、易用性、稳定性等方面,旨在发现和修复潜在的问题和缺陷。通过进行全面的确认测试,软件企业可以…

操作系统学习笔记--进程与线程

进程 概念 不同的角度有不同的定义 进程是程序的一次执行过程进程是一个程序及其数据在处理机上顺序执行时所发生的活动进程是具有独立功能的程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位 进程:是动态的,是…

Flink-SQL join 优化 -- MiniBatch + local-global

背景 问题1. 近期在开发flink-sql期间,发现数据在启动后,任务总是进行重试,运行一段时间后,container心跳超时,内存溢出,作业无法进行正常工作 023-10-07 14:53:30,408 | INFO | [flink-akka.actor.defa…

关于需要用到暂停的unity游戏

在做游戏的时候,我们经常需要用到Time.timescalse 0;来暂停游戏 但是,我们有些其他的东西,却不想它们被暂停影响了。 例如 1、Dotween 如上图增加一段.SetUpdate(true)即可 2、animator public Animator Ani;public void Firs…

链表(7.27)

3.3 链表的实现 3.3.1头插 原理图: newnode为新创建的节点 实现: //头插 //让新节点指向原来的头指针(节点),即新节点位于开头 newnode->next plist; //再让头指针(节点)指向新节点&#…

【亲测】简易商城小程序源码-易优CMS后台

易优小程序是基于前端开源小程序后端易优CMS标签化API接口, 是一套开源、快速搭建个性化需求的小程序CMS。轻量级TP底层框架,前后端分离, 标签化API接口可对接所有小程序,支持二次开发。即使小白用户也能轻松搭建制作一套完整的线…

90后整顿秦始皇老板

我的日常就像跑步机上急速前行的仓鼠,使劲往前冲,心有余力力有限。 我在一个电商运营公司做策划和写文案,每天总是加不完的班,从来没见过下午六点钟的太阳。 我做文案吗?唉,说实话,我倒觉得大…

C#(Csharp)我的基础教程(二)(我的菜鸟教程笔记)-属性和字段的探究与学习

目录 1、字段字段特点:2、属性属性的特点 1、字段 字段是定义在方法外面的变量,是成员变量,主要是为了类的内部数据交换使用,字段一般是用private修饰,也可以用readonly修饰,表示只读字段,其它…

10月底下架!亚马逊新增5大售前审核品类,提醒这6大站点卖家注意

近期,不少加拿大站、沙特阿拉伯站、埃及站、瑞典站、波兰站以及比利时站卖家陆续收到了亚马逊合规政策要求邮件,包括加拿大站对于“带拉绳的童装”、“水壶”、“玻璃门和围栏”三个品类,沙特阿拉伯、埃及对于“面向婴幼儿的食品”品类&#…

如何在C++项目中用C#运行程序调试C++ DLL

问题描述 在C#项目中调用C DLL时报错或者运行结果不符,此时需要运行C#项目并在C中加入断点进行调试 项目准备 项目一:C#项目(该项目调用C DLL)项目二:C项目(生成C DLL) 这两个项目不需要在同…

BGP服务器租用腾讯云和阿里云价格对比

BGP云服务器像阿里云和腾讯云均是BGP多线网络,速度更快延迟更低,阿里云BGP服务器2核2G3M带宽优惠价格108元一年起,腾讯云BGP服务器2核2G3M带宽95元一年起,阿腾云atengyun.com分享更多云服务器配置如2核4G、4核8G、8核16G等配置价格…

VALSE2023-快速总结

会议快速总结 1. 前言2. 热点词2.1 自监督预训练2.2 MIM(Masked Image Modeling)2.3 MAE(Masked Autoencoders)2.4 clip(Contrastive Language-Image Pre-Training)模型2.5 对比学习2.6 扩散模型(diffustion model)2.7 Nerf&#…

超高速PCIe实时运动控制卡与应用方案将亮相深圳NEPCON,正运动技术邀您前来体验!

助力电子半导体设备加速国产替代导入,正运动超高速PCIe运动控制卡可覆盖电子半导体大部分工艺流程应用,提供高速高精稳定的运动控制解决方案。 ■展会名称: NEPCON ASIA 2023亚洲电子生产设备暨微电子工业展(以下简称“2023亚洲…

c#设计模式-行为型模式 之 中介者模式

🚀简介 又叫调停模式,定义一个中介角色来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。 从下右图中可以看到,任何一个类的变 动,只会影响的类本身,以及…