详解javascript立即执行函数表达式IIFE
一、IIFE解释
全拼Imdiately Invoked Function Expression,立即执行的函数表达式。
像如下的代码所示,就是一个匿名立即执行函数:
(function(window, undefined){ // 代码... })(window);
二、括号的意义
2.1 包住function(){}的括号的意义
这个括号的目的,是为了把function(){}转化为表达式。像一些库的源码,喜欢用如下方式代替:
~function(){ // 代码... }();
或者这种方式:
+function(){ // 代码... }();
其实,作用都一样,都是把function(){}转化成一个可执行的表达式,方便执行。
如果去掉该括号,则会报错。因为单纯的function(){}不是可执行的表达式,会直接报错。如下图:
2.1 第二个括号的意义
理解了第一个括号的意义,第二个括号就很简单了,就是执行表达式了。
三、参数的意义
以这段代码为例子,讲解参数
var wall = {}; (function(window, WALL, undefined){ })(window, wall);
参数分为形参和实参。
function(window, WALL, undefined)三个参数为形参,第二个括号(window, wall)的两个参数为实参。
也即可以理解为 window == window,wall == WALL。
2.1 普通形参
普通形参是指由window和wall这样的实际变量传入指定,可以为任何类型的变量。一个形参就对应一个实参
2.2 特殊形参undefined
为什么形参要多写一个undefined,这是一个很有趣的话题。
可以知道这个示例,实参只有两个,而形参有三个。所以在函数执行的时候,形参undefined会默认赋值为undefined。
形参undefined的作用如下:
2.2.1 防止特殊值undefined被恶意代码篡改。
IE6等低版本浏览器,undefined是支持被修改的。而这个特殊值被修改后,像以下这种判断就失效了。
if(wall == undefined){ // 代码... }
所以,这里多加一个形参的目的就是为了防止这种情况发生。只要在这个IIFE作用域内,undefined就能够正常获取到。
2.2.2 压缩代码可以压缩undefined
因为undefined作为形参,像YUI compressor这种类型的代码压缩工具,可以将其相关的值进行压缩,减小文件的体积。
四、写法解析
4.1 普通写法
var wall = {}; // 声明定义一个命名空间wall // 定义方法 (function(window, WALL, undefined){ // 给wall命名空间绑定方法say WALL.say = function(){ console.log('hello'); }; })(window, wall); (function(window, WALL, undefined){ // 给wall命名空间绑定方法 whoIam WALL.whoIam = function(){ console.log('wall'); }; })(window, wall); // 调用 wall.say(); wall.whoIam();
先定义一个命名空间,然后再给这个命名空间加东西。这是最普遍的写法,也是最好理解的。
不足的地方就是必须先声明一个命名空间,然后才能执行相关的绑定代码。存在顺序加载的问题。
4.2 放大模式
var wall = (function(window, WALL, undefined){ if(typeof WALL == 'undefined'){ WALL = {}; } // 给wall命名空间绑定方法say WALL.say = function(){ console.log('hello'); } return WALL; // 返回引用 })(window, wall); var wall = (function(window, WALL, undefined){ if(typeof WALL == 'undefined'){ WALL = {}; } // 给wall命名空间绑定方法 whoIam WALL.whoIam = function(){ console.log('wall'); } return WALL; // 返回引用 })(window, wall); // 调用 wall.say(); wall.whoIam();
放大模式的好处就是,可以不用考虑代码加载的先后顺序。
因为js允许wall变量进行重复var声明,所以这段代码是可以执行的。
我可以把IIFE函数拆分成多个文件进行加载,而不会出现普通写法需要注意的问题。
需要注意的点:
1.IIFE的头部,都要先进行检查命名空间是否已经实例化,如果还没实例化,则进行实例化。
2.IIFE的尾部,都要return命名空间的引用,使后续代码能够得到最新的wall命名空间内容。
4.3 宽放大模式
(function(window, WALL, undefined){ // 给wall命名空间绑定方法say WALL.say = function(){ console.log('hello'); } })(window, window.wall || (window.wall = {})); (function(window, WALL, undefined){ // 给wall命名空间绑定方法 whoIam WALL.whoIam = function(){ console.log('wall'); } })(window, window.wall || (window.wall = {})); // 调用 wall.say(); wall.whoIam();
宽放大模式的重点注意的地方:就是在实参部分的window.wall || (window.wall = {})。
用||运算符进行取巧。
如果window.wall是已经实例化的,非not defined。则直接返回window.wall的引用,赋值给形参WALL。不会执行||运算符后面的内容。
如果window.wall还未实例化,则进行实例化。这里要注意的点是实例化是一个赋值操作,需要用括号包起来,变成表达式去执行,才不会报错。
表达式(window.wall = {})执行完毕后,会返回新对象window.wall的引用。
宽放大模式的好处:是可以切割成多个文件进行加载,而不必考虑文件加载的先后顺序,不存在强耦合关系。
当然,如果IIFE里面的方法互相引用,还是存在加载依赖的问题。这个问题可以用加载器Require.js等工具解决,这里就不讨论了。
五、分文件加载IIFE要注意的点
;(function(window, WALL, undefined){ // 给wall命名空间绑定方法say WALL.say = function(){ console.log('hello'); } })(window, window.wall || (window.wall = {}));
眼尖的已经看出区别了,就是文件开始的地方,先写上分号;。
这样,多个文件合并的时候,才不会出现收尾相接,代码出现错乱的问题。比如下面这种情况:
// a.js 文件 wall.log() // b.js 文件 (function(window, WALL, undefined){ // 给wall命名空间绑定方法say WALL.say = function(){ console.log('hello'); } })(window, window.wall || (window.wall = {}));
由于a.js文件的wall.log()少写了分号,跟b.js文件合并后,js就会认为‘wall.log()(...)'是需要这么执行的,结果代码就报错了。
觉得不错的,可以关注模块化这个系列的文章,容我后续码字,敬请期待!
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持脚本之家!
相关文章
- 本篇文章主要分享了通过window.navigator来判断浏览器及其版本信息的实例代码。具有一定的参考价值,下面跟着小编一起来看下吧...2017-01-23
- 这篇文章主要介绍了js如何实现浏览器打印功能,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下...2020-07-15
- 这篇文章主要给大家介绍了关于Nest.js参数校验和自定义返回数据格式的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-28
- 下面小编就为大家带来一篇利用JS实现点击按钮后图片自动切换的简单方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2016-10-25
- 作为前端,一直以来都知道HTTP劫持与XSS跨站脚本、CSRF跨站请求伪造。防御这些劫持最好的方法是从后端入手,前端能做的太少。而且由于源码的暴露,攻击者很容易绕过防御手段。但这不代表我们去了解这块的相关知识是没意义的,本文的许多方法,用在其他方面也是大有作用。...2021-05-24
- 这篇文章主要介绍了js实现调用网络摄像头及常见错误处理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-07
- 这篇文章主要为大家详细介绍了js+css实现回到顶部按钮back to top回到顶部按钮,感兴趣的小伙伴们可以参考一下...2016-03-03
- 这篇文章主要为大家详细介绍了JS实现随机生成验证码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-06
- 这篇文章主要为大家详细介绍了js实现上传图片及时预览的相关资料,具有一定的参考价值,感兴趣的朋友可以参考一下...2016-05-09
- 那么今天我就用JavaScript代码来实现这个效果吧,那么首先介绍一下整个的思路,首先我们先将确定输入密码的位数,我的需求是5位,那么就用一个div标签包住5个input标签...2016-01-02
- 这篇文章主要介绍了js组件SlotMachine实现图片切换效果制作抽奖系统的相关资料,需要的朋友可以参考下...2016-04-19
- Vue.js通过简洁的API提供高效的数据绑定和灵活的组件系统.这篇文章主要介绍了vue.js 表格分页ajax 异步加载数据的相关资料,需要的朋友可以参考下...2016-10-20
- 为了网站的安全性,很多朋友都把密码设的比较复杂,但是如何密码不能明显示,不知道输的是对是错,为了安全起见可以把密码显示的,那么基于js代码如何实现的呢?下面通过本文给大家介绍JavaScript实现表单密码的隐藏和显示,需要的朋友参考下...2016-03-03
- 这篇文章主要为大家详细介绍了js实现列表按字母排序,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-08-11
- 这篇文章主要介绍了基于JavaScript实现文字超出部分隐藏 的相关资料,需要的朋友可以参考下...2016-03-01
- 本文给大家介绍的是nodejs实现使用阿里大鱼短信API发送消息的方法和代码,有需要的小伙伴可以参考下。...2016-01-20
- 这篇文章主要介绍了JS实现响应鼠标点击动画渐变弹出层效果代码,具有非常自然流畅的动画过度效果,涉及JavaScript针对鼠标事件的响应及页面元素样式的动态操作相关技巧,需要的朋友可以参考下...2016-03-28
- 系统的学习了一下angularjs,发现angularjs的有些思想根php的模块smarty很像,例如数据绑定,filter。如果对smarty比较熟悉的话,学习angularjs会比较容易一点,这篇文章给大家介绍angularjs filter用法详解,感兴趣的朋友一起学习吧...2015-12-29
- 这次文章要给大家介绍的是node.JS md5加密中文与php结果不一致怎么办,不知道具体解决办法的下面跟小编一起来看看。 因项目需要,需要Node.js与PHP做接口调用,发现nod...2017-07-06
- 这篇文章主要给大家介绍了一个关于JS正则匹配的踩坑记录,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-13