模块化写法-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()(...)’是需要这么执行的,结果代码就报错了。
觉得不错的,可以关注模块化这个系列的文章,容我后续码字,敬请期待!
阅读原文:http://www.jianshu.com/p/4dbf4a4c8ebb
模块化写法-IIFE解析的更多相关文章
- JS模块化写法
/* 模块化写法*/ var Person=function(){ var name='Jone', age='24', sex='male'; function createIdea(){ //{. ...
- require.js模块化写法
模块化 模块就是实现特定功能的一组方法.只要把不同的函数(以及记录状态的变量)简单地放在一起,就算是一个模块. 下述两种写法等价 exports 对象是当前模块的导出对象,用于导出模块公有方法和属性. ...
- JS模块化写法(转)
一.原始写法 模块就是实现特定功能的一组方法. 只要把不同的函数(以及记录状态的变量)简单地放在一起,就算是一个模块. function m1(){ //... } function m2(){ // ...
- js的模块化写法
记得前两天自己写一个动画首页,动画很复杂,我用的fullpage虽然相对比较简单,但是每个页面的animation各有差异,需要相对控制,估计有上千行的js代码,写的心情乱糟糟的. 如何让代码量巨大, ...
- node.js模块化写法入门
子模块的写法: function SVN(){ console.log('svn initialized'); return this; } function getInstance() { cons ...
- for 循环新的写法==列表解析
1. (for x in L1) 是一个可迭代对象: 2. 列表解析比for 循环快,列表解析的迭代在解释器内部是以C语言速度执行, 而不是手动python代码执行: (x+10 for x in L ...
- 基于RequireJS和JQuery的模块化编程——常见问题解析
由于js的代码逻辑越来越重,一个js文件可能会有上千行,十分不利于开发与维护.最近正在把逻辑很重的js拆分成模块,在一顿纠结是使用requirejs还是seajs的时候,最终还是偏向于requirej ...
- 几种交换两个数函数(swap函数)的写法和解析
#include <iostream> using namespace std; /*值传递,局部变量a和b的值确实在调用swap0时变化了,当结束时,他们绳命周期结束*/ void sw ...
- js模块化 javascript 模块化 闭包写法 闭包模块化写法
var main = main || {}; ; (function (main) { 'use strict'; //私有变量 var _s1 = 'Hello '; var _s2 = 'Worl ...
随机推荐
- Arduino线程库ProtoThreads
参考: Arduino线程库ProtoThreads 一个“蝇量级” C 语言协程库
- input有许多,点击按钮使用form传递文本框的值
input有许多,点击按钮使用form传递文本框的值 <form name="form1" method="post" action="< ...
- 在Action类中获得HttpServletResponse对象的四种方法
在struts1.xAction类的execute方法中,有四个参数,其中两个就是response和request.而在Struts2中,并没有任何参数,因此,就不能简单地从execute方法获得Ht ...
- hadoop如何查看文件系统
1.查看当前的文件系统 [root@hadoopmaster bin]# . itemsdrwxr 00 00 /user 当然也可以以浏览器中这样查看localhost:50070 这就是had ...
- transform和transition
作者:zccst 例如:图片墙 .另外还有,便签墙 使用的样式: 1,正常情况下 ul#index_cards li { background: url("../images/ca ...
- BMP085气压传感器驱动
BMP085是新一代的小封装气压传感器,主要用于气压温度检测,在四轴飞行器上可以用作定高检测,该传感器属于IIC总线接口,依然沿用标准IIC驱动程序 使用该传感器需要注意的是我们不能直接读出转换好的二 ...
- iOS 发布流程
1.登陆苹果开发者中心http://developer.apple.com(99美元账号) 2.进入itunes connect 3.选择Manage Your Apps 4.选择Add New Ap ...
- IOS第三方数据库--FMDB
iOS中原生的SQLite API在使用上相当不友好,在使用时,非常不便.于是,就出现了一系列将SQLite API进行封装的库,例如FMDB.PlausibleDatabase.sqlitepers ...
- IOS 实现TXT文本自动识别编码的方法
from :http://kyoworkios.blog.51cto.com/878347/1344013 TXT识别编码是个复杂的问题.幸好有c/c++的一个库能识别. 库的叫uchardet,可以 ...
- scrapy+Lucene搭建小型搜索引擎
Reference: http://blog.csdn.net/napoay/article/details/51477586 一.选题 工程类搜索型: 定向采集 3-4 个新闻网站, 实现这些网站信 ...