JavaScript的IIFE(即时执行方法)
(1)标准写法
- (function (window, document, undefined) {
- //
- })(window, document);
(2)作用域Scope
JavaScript有function作用域,所以function首先创建一个私有的作用域,在执行的时候都会创建一个执行上下文。
- (function (window, document, undefined) {
- var name = '张三';
- })(window, document);
- console.log(name); // 因为作用域不同,这里的name未定义。
调用方法一:
- var logMyName = function (name) {
- console.log(name);
- };
- logMyName('李四');
调用方法二:
- var logMyName = (function (name) {
- console.log(name);
- })('王五');
需要注意的是需要用括号把函数内容括起来:
- function () {
- // ...
- })();
没有括号的话会报语法错:
- function () {
- // ...
- }();
也可以强制JavaScript识别代码(一般很少这么用):
- !function () {
- // ...
- }();
- +function () {
- // ...
- }();
- -function () {
- // ...
- }();
- ~function () {
- // ...
- }();
比如:
- var a = !function () {
- return true;
- }();
- console.log(a); // 打印输出 false
- var b = (function () {
- return true;
- })();
- console.log(b); // 打印输出 true
(3)参数Arguments
- 介绍IIFE
- IIFE的性能
- 使用IIFE的好处
- IIFE最佳实践
- jQuery优化
在Bootstrap源码(具体请看《Bootstrap源码解析》)和其他jQuery插件经常看到如下的写法:
- +function ($) {
- }(window.jQuery);
这种写法称为:
IIFE (Imdiately Invoked Function Expression 立即执行的函数表达式)。
一步步来分析这段代码。
先弄清函数表达式(function expression)和 函数声明(function declaration)的区别:
函数表达式 Function Expression - var test = function() {};
函数申明 Function Declaration - function test() {};
函数表达式中的函数可以为匿名函数,也可以有函数名,但是该函数实际上不能直接使用,只能通过表达式左边的变量 a 来调用。
- var a = function(){
- alert('Function expression');
- }
- var b = new a();
函数声明时必须有函数名。
- function a(){
- alert('Function declaration');
- }
- a();
这是一个匿名函数。
- function () {
- }
你也许注意到匿名函数在console下会报错。console的执行和报错如下:
function(){}
通过一元操作符+变成了函数表达式。也可以使用 - ~ !等其他一元运算符或者括号,目的是为了引导解析器,指明运算符附近是一个表达式。以下是三种经典方式 :
- +function () {
- };
- (function () {
- });
- void function() {
- };
函数表达式通过 末尾的() 来调用并运行。就是一个IIFE。
- +function () {
- }();
- (funtion () {
- })();
代码性能
运算符:+加-减!逻辑非~位取反,返回NaN(Not A Number)。
“()”组运算符:返回表达式的执行结果undefined。
void:按运算符结合语句执行,返回 undefined。
这几种的性能对比结果:

可见+性能最差(在Firefox下差距更明显),其他几种都差不多。不过IIFE只执行一遍,对js执行效率的影响特别小,使用哪种还是看个人爱好。
传参,为了避免$与其他库或者模板申明冲突,window.jQuery 作为参数传递。
- +function (x) {
- console.log(x);
- }(3);
- +function ($) {
- }(window.jQuery);
使用IIFE的好处
总结有4点:提升性能、有利于压缩、避免冲突、依赖加载
1、减少作用域查找。使用IIFE的一个微小的性能优势是通过匿名函数的参数传递常用全局对象window、document、jQuery,在作用域内引用这些全局对象。JavaScript解释器首先在作用域内查找属性,然后一直沿着链向上查找,直到全局范围。将全局对象放在IIFE作用域内提升js解释器的查找速度和性能。
传递全局对象到IIFE的一段代码示例:
- // Anonymous function that has three arguments
- function(window, document, $) {
- // You can now reference the window, document, and jQuery objects in a local scope
- }(window, document, window.jQuery); // The global window, document, and jQuery objects are passed into the anonymous function
2、有利于压缩。另一个微小的优势是有利于代码压缩。既然通过参数传递了这些全局对象,压缩的时候可以将这些全局对象匿名为一个字符的变量名(只要这个字符没有被其他变量使用过)。如果上面的代码压缩后会变成这样:
- // Anonymous function that has three arguments
- function(w, d, $) {
- // You can now reference the window, document, and jQuery objects in a local scope
- }(window, document, window.jQuery); // The global window, document, and jQuery objects are passed into the anonymous function
3、避免全局命名冲突。当使用jQuery的时候,全局的window.jQuery对象 作为一个参数传递给$,在匿名函数内部你再也不需要担心$和其他库或者模板申明冲突。 正如James padolsey所说:
An IIFE protects a module’s scope from the environment in which it is placed.
4、通过传参的方式,可以灵活的加载第三方插件。(当然使用模块化加载更好,这里不考虑。)举个例子,如果a页面需要使用KindEditor,a.html引入kindeditor.js 和 a.js
你可能会这么写 a.js:
- $(function() {
- var editor
- KindEditor.ready(function(K) {
- editor = K.create('textarea[data-name="kindeditor"]', {
- resizeType : 1
- })
- })
- })
b页面不需要使用Kindeditor,没有引入kindeditor.js。但是在合并JS代码后,b页面也会执行a.js中的代码,页面报错Uncaught ReferenceError: KindEditor is not defined。也就是b页面执行了KindEditor,难道所有页面都要加载Kindeditor源文件?
可以这么修改a.js,将KindEditor变量参数化,通过给立即执行的函数表示式的参数赋值,那么其他页面都不需要加载Kindeditor源文件
- +function( KindEditor){
- var editor
- if(KindEditor){
- KindEditor.ready(function(K) {
- editor = K.create('textarea[data-name="kindeditor"]', {
- resizeType : 1
- })
- })
- }
- }(KindEditor || undefined)
IIFE最佳实践
反对使用IIFE的其中一个理由是可读性差,如果你有大量的JavaScript代码都在一段IIFE里,要是想查找IIFE传递的实际参数值,必须要滚动到代码最后。幸运的是,你可以使用一个更可读的模式:
- (function (library) {
- // Calls the second IIFE and locally passes in the global jQuery, window, and document objects
- library(window, document, window.jQuery);
- }
- // Locally scoped parameters
- (function (window, document, $) {
- // Library code goes here
- }));
这种IIFE模式清晰的展示了传递了哪些全局对象到你的IIFE中,不需要滚动到长文档的最后。
jQuery优化
一段看上去写法有点像的代码。大部分项目用这段代码做作用域,这段代码会在DOM加载完成时初始化jQuery代码。
- $(function(){
- });
这种写法等同于
- $(document).ready(function(){
- // 在DOM加载完成时初始化jQuery代码。
- });
- $(window).load(function(){
- // 在图片等媒体文件加载完成时,初始化jQuery代码。
- });
结合IIFE的最佳实践,更好的写法是,立即执行document ready
- +function ($) {
- $(function(){
- })
- }(window.jQuery)
最佳实践
- // IIFE - Immediately Invoked Function Expression
- +function(yourcode) {
- // The global jQuery object is passed as a parameter
- yourcode(window.jQuery, window, document);
- }(function($, window, document) {
- // The $ is now locally scoped
- // Listen for the jQuery ready event on the document
- $(function() {
- // The DOM is ready!
- }));
具体请看工程师,请优化你的代码
其他
在Bootstrap和其他插件中经常看到如下写法:
- +function ($) { "use strict";
- }(window.jQuery);
关于字符串"use strict";请看严格模式
传递参数给IIFE
- (function (window) {
- // 这里可以调用到window
- })(window);
- (function (window, document) {
- // 这里可以调用到window和document
- })(window, document);
undefined参数
在ECMAScript 3中undefined是mutable的,这意味着可以给undefined赋值,而在ECMASCript 5的strict模式('use strict';)下是不可以的,解析式时会报语法错。
所以为了保护IIFE的变量需要undefined参数:
- (function (window, document, undefined) {
- // ...
- })(window, document);
即使有人给undefined赋值也没有关系:
- undefined = true;
- (function (window, document, undefined) {
- // undefined指向的还是一个本地的undefined变量
- })(window, document);
(4)代码压缩Minifying
- (function (window, document, undefined) {
- console.log(window); // window对象
- })(window, document);
代码压缩后,undefined的参数不再存在,但是由于 (window, document); 的调用没有传递第三个参数,所有c依然是一个本地undefined变量,所有参数中undefined的名字是无所谓什么的,只需要知道他指向的是一个undefined变量。
- (function (a, b, c) {
- console.log(a); // window对象
- })(window, document);
除undefined变量外,其他的所有希望只在函数内部有效的变量都可以通过参数传递进去,比如以下的jQuery对象。
- (function ($, window, document, undefined) {
- // 使用 $ 指向 jQuery,比如:
- // $(document).addClass('test');
- })(jQuery, window, document);
- (function (a, b, c, d) {
- // 代码会被压缩为:
- // a(c).addClass('test');
- })(jQuery, window, document);
JavaScript的IIFE(即时执行方法)的更多相关文章
- 在WebBrowser中执行javascript脚本的几种方法整理(execScript/InvokeScript/NavigateScript) 附完整源码
[实例简介] 涵盖了几种常用的 webBrowser执行javascript的方法,详见示例截图以及代码 [实例截图] [核心代码] execScript方式: 1 2 3 4 5 6 7 8 9 1 ...
- javascript实现每秒执行一次的方法
javascript实现每秒执行一次的方法 <pre> i=0; function showzhandou() { $('.zhandouresult p').eq(i).fadeIn() ...
- 【JavaScript专题】--- 立即执行函数表达式
一 什么是立即执行函数表达式 立即执行函数表达式,其实也可以叫初始化函数表达式,英文名:IIFE,immediately-inovked-function expression.立即执行函数表达式就是 ...
- javascript中数组常用的方法
在JavaScript中,数组可以使用Array构造函数来创建,或使用[]快速创建,这也是首选的方法.数组是继承自Object的原型,并且他对typeof没有特殊的返回值,他只返回'object'. ...
- [转]Javascript中的自执行函数表达式
[转]Javascript中的自执行函数表达式 本文转载自:http://www.ghugo.com/javascript-auto-run-function/ 以下是正文: Posted on 20 ...
- 深入理解javascript中的立即执行函数(function(){…})()
投稿:junjie 字体:[增加 减小] 类型:转载 时间:2014-06-12 我要评论 这篇文章主要介绍了深入理解javascript中的立即执行函数,立即执行函数也叫立即调用函数,通常它的写法是 ...
- Jquery中$(document).ready()与传统JavaScript中的window.onload方法的区别(2016/8/3)
Jquery中$(document).ready()的作用类似于传统JavaScript中的window.onload方法,不过与window.onload方法还是有区别的. 1.执行时间 ...
- ASP.NET CS文件中输出JavaScript脚本的3种方法以及区别
Response.Write 与 Page.ClientScript.RegisterStartupScript 与 Page.ClientScript.RegisterClientScriptB ...
- JavaScript之call()和apply()方法详解
简介:apply()和call()都是属于Function.prototype的一个方法属性,它是JavaScript引擎内在实现的方法,因为属于Function.prototype,所以每个Func ...
随机推荐
- UVA 12050 - Palindrome Numbers 模拟
题目大意:给出i,输出第i个镜像数,不能有前导0. 题解:从外层开始模拟 #include <stdio.h> int p(int x) { int sum, i; ;i<=x;i+ ...
- word2007如何进行批注
在正常的办公或者学校撰写论文,请别人进行提出修改意见是不可避免的,在word2007中提供了批注修改模式,十分方便,给撰写文档和批阅文档的人带来了极大的方便.本节介绍如何在word2007中进行批注及 ...
- van Emda Boas
van Emda Boas维护了一个整数集合[0,Max)(无重复),其中Max必须等于2的正整数次幂.它支持以下操作:(1)插入一个数字;(2)删除一个数字:(3)询问某一个数字在不在这个集合中:( ...
- 当插入数据失败时,防止mysql自增长字段的自增长的方法
问题描述: 当mysql设置了自增长字段时(注意:一个表中只能设置一个自增长字段,可以不是主键,但必须是键 ),如果插入数据失败,那么自增长字段仍然会占用这个自增长值,再次成功插入数据时就会造成断层. ...
- oracle学习笔记——配置环境
题记:最近再学oracle,于是按照这本经典的书<Oracle Database 9i/10g/11g编程艺术>来学习. 配置环境 如何正确建立SCOTT/TIGER演示模式 需要建立和运 ...
- HDU 1728 逃离迷宫
[题目描述 - Problem Description] 给定一个m × n (m行, n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,glo ...
- jQuery 预习视频
1.事件补充 <input type="button" onclick="CheckAll('#edit_mode','#tb1');" value=&q ...
- NYOJ 93 汉诺塔(三)
汉诺塔(三) 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 在印度,有这么一个古老的传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针.印度 ...
- Java中ArrayList相关的5道面试题
本文参考了 <关于ArrayList的5道面试题 > 1.ArrayList的大小是如何自动增加的? 这个问题我想曾经debug过并且查看过arraylist源码的人都有印象,它的过程是: ...
- python成长之路【第一篇】:python简介和入门
一.Python简介 Python(英语发音:/ˈpaɪθən/), 是一种面向对象.解释型计算机程序设计语言. 二.安装python windows: 1.下载安装包 https://www.pyt ...