模块化写法-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 ...
随机推荐
- Memcache第一篇---基础教程
Memcache是什么 Memcache是danga.com的一个项目,最早是为 LiveJournal 服务的,目前全世界不少人使用这个缓存项目来构建自己大负载的网站,来分担数据库的压力. 它可以应 ...
- 关于JAVA中hashCode
hash code 即散列码根据对象计算出的一个整型值,散列码是没有规律的. 如果两个对象相等(equal() 返回true),则hashCode一定相等,如果两个对象hashCode相等,则对象不一 ...
- 《算法导论》2.3-7 检查集合中是否存在两数字和为指定的X--算法和证明
习题2.3-7:设计一个算法,对于一个给定的包含n个整数的集合S和另一个给定的整数X,该算法可以在时间内确定S中是否存在两个元素,使得它们的和恰为X. 解题思路:首先应该想到的是先用一个的排序算法对S ...
- php smarty
摘自:http://linux.chinaitlab.com/PHP/38324.html 刚开始接触模版引擎的 PHP 设计师,听到 Smarty 时,都会觉得很难.其实笔者也不例外,碰都不敢碰一 ...
- zeromq随笔
ZMQ (以下 ZeroMQ 简称 ZMQ)是一个简单好用的传输层,像框架一样的一个 socket library,他使得 Socket 编程更加简单.简洁和性能更高.是一个消息处理队列库,可在多个线 ...
- 微软企业库DBBA的研究
Summary:如何入门使用Data Access Application Block,可以参考Enterprise Library 3.1中文帮助:数据访问应用程序块.这篇文章侧重在DAAB工作原理 ...
- Firefox恢复书签
Firefox虽然有网络同步功能,但是网络账户中没有保存历史书签.一旦电脑故障,书签可能会丢失,更要命的是自动同步後,网上书签也被覆盖的一干二净.怎么办呢? 大多数时候还是可以在本机找回书签 1:打开 ...
- Beautifulsoup 和selenium 的查询
Selenium There are vaious strategies to locate elements in a page. You can use the most appropriate ...
- centos5.5 Apache2 Web 服务器的安装
# vi /etc/httpd/conf/httpd.conf 把以下虚拟机的配置加在 httpd.conf 文件末尾即可 NameVirtualHost *:80 // ...
- 最多两次股票交易-Best Time to Buy and Sell Stock III
Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...