摘要:打开源码,首先你会看到这样的代码结构这是一个自调用匿名函数。模式,是自执行函数的高级模式,可以非常方便的在各个匿名闭包中以全局对象调用闭包函数。
打开jQuery源码,首先你会看到这样的代码结构:
(function(window,undefined ){
//
})();
这是一个自调用匿名函数。什么东东呢?在第一个括号内,创建一个匿名函数;第二个括号,立即执行
为什么要创建这样一个“自调用匿名函数”呢?
通过定义一个匿名函数,创建了一个“私有”的命名空间,该命名空间的变量和方法,不会破坏全局的命名空间。这点非常有用也是一个JS框架必须支持的功能,jQuery被应用在成千上万的JavaScript程序中,必须确保jQuery创建的变量不能和导入他的程序所使用的变量发生冲突。
接下来看看在 自调用匿名函数 中都实现了什么功能,按照代码顺序排列:
(function( window, undefined ) {
// 构造jQuery对象 var jQuery = function( selector, context ) { return new jQuery.fn.init( selector, context, rootjQuery ); } // 工具函数 Utilities // 异步队列 Deferred // 浏览器测试 Support // 数据缓存 Data // 队列 queue // 属性操作 Attribute // 事件处理 Event // 选择器 Sizzle // DOM遍历 // DOM操作 // CSS操作 // 异步请求 Ajax // 动画 FX // 坐标和大小 window.jQuery = window.$ = jQuery;
})(window);
匿名函数从语法上叫函数直接量,JavaScript语法需要包围匿名函数的括号,事实上自调用匿名函数有两种写法:
(function() {
console.info( this ); console.info( arguments );
}( window ) );
(function() {
console.info( this ); console.info( arguments );
})( window );
为什么要传入window呢?
通过传入window变量,使得window由全局变量变为局部变量,当在jQuery代码块中访问window时,不需要将作用域链回退到顶层作用域,这样可以更快的访问window;这还不是关键所在,更重要的是,将window作为参数传入,可以在压缩代码时进行优化,看看jquery-1.6.1.min.js: (function(a,b){})(window); // window 被优化为 a
通过以上的介绍,我们大概了解通过()可以使得一个函数表达式立即执行。
匿名函数作为一个“容器”,“容器”内部可以访问外部的变量,而外部环境不能访问“容器”内部的变量,
所以 ( function(){…} )() 内部定义的变量不会和外部的变量发生冲突,俗称“匿名包裹器”或“命名空间”。
(function () {
// ... 所有的变量和function都在这里声明,并且作用域也只能在这个匿名闭包里 // ...但是这里的代码依然可以访问外部全局的对象
}());
同下面
(function () {/ 内部代码 /})();
通俗的讲,()就是用来求值的,因此这个()任何时候都不能为空,因为它是要计算的。函数解析它只会解析到 {}为止,不会解析到 ()的。
把表达式放在()中会返回表达式的值; 把函数放在()中会返回函数本身;(function(){}()); 如果()紧跟在函数后面,就是表示在调用函数,即对函数求值:(function(){})();
(function() {
//自执行函数中的内部变量,外部是无法访问的 var name = "kevin";
})( window );
name //undefined,无法获取name的值
代码在运行过程中,会优先解析 【巳声明的函数】;
而函数表达式是当执行到它时,才会解析; 匿名函数是不会多带带写的,因此它的执行是需要其它函数的调用,通常看到的匿名函数,都是当作参数被传递的。而立即执行函数它本身就是个匿名函数, js代码执行的顺序: //巳声明的函数 function test(){} //匿名函数 function (){} //函数表达式 var test = function(){} //立即执行函数 (function(){})();
立即执行函数配合闭包,在模块化中的应用,其中要明白几个点:
1、要在函数体后面加括号就能立即调用,则这个函数必须是函数表达式,不能是函数声明; 2、立即执行函数可以当作是一个私有作用域,作用域内部可以访问外部的变量,而外部环境是不能访问作用域内部的变量的,因此,立即执行函数是一个封闭的作用域,不会和外部作用域起冲突。 JQuery使用的就是这种方法,将JQuery代码包裹在( function (window,undefined){…jquery代码…} (window)中,在全局作用域中调用JQuery代码时,可以达到保护JQuery内部变量的作用。 3、Module模式,是自执行函数的高级模式,可以非常方便的在各个匿名闭包中以全局对象调用闭包函数。有兴趣可以查看:http://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html Module 模式为: a.创建一个立即调用的匿名函数表达式 b.return一个变量,其中这个变量里包含你要暴露的东西 c.返回的这个变量将赋值给window
(function () {
var i = 0; return { get: function () { return i; }, set: function (val) { i = val; }, increment: function () { return ++i; } };
} (window));
// window作为一个带有多个属性的全局对象,上面的代码对于属性的体现其实是方法,它可以这样调用: window.get(); // 0 window.set(3); window.increment(); // 4 window.increment(); // 5 window.i; // undefined 因为i不是返回对象的属性 i; // 引用错误: i 没有定义(因为i只存在于闭包)
/上面就是关于自调用匿名函数的解析,那么这样的函数它是怎么被调用的呢?*/
/下面是关于全局变量的调用,也就是匿名闭包函数的调用*/
再次搬出Module模式,有兴趣可以查看:http://www.cnblogs.com/TomXu/...
Module 模式,也就是匿名闭包的创建与调用:
a.创建一个立即调用的匿名函数表达式 b.return一个变量,其中这个变量里包含你要暴露的东西 c.返回的这个变量将赋值给window
window(或者是任意一个全局对象)作为一个带有多个属性的全局对象,也可以把window当成一个参数,以对象的方式,在其它函数中实现调用。用下面的例子说明:
(function ($, YAHOO) {
// 这里,我们的代码就可以使用全局的jQuery对象了,YAHOO也是一样 $.aa = function(){ //code }
} (jQuery, YAHOO));
//调用 jQuery.aa();
下面是一个标准的Module模式,通过匿名函数的返回值来返回这个全局变量:
var blogModule = (function () {
var my = {}, privateName = "博客园"; function privateAddTopic(data) { // 这里是内部处理代码 } my.Name = privateName; my.AddTopic = function (data) { privateAddTopic(data); }; return my;
} ());
//调用 blogModule.my();
在一些大型项目里,将一个功能分离成多个文件是非常重要的,因为可以多人合作易于开发。再回头看看上面的全局参数导入例子,我们能否把blogModule自身传进去呢?答案是肯定的,我们先将blogModule传进去,添加一个函数属性,然后再返回就达到了我们所说的目的:
var blogModule = (function (my) {
my.AddPhoto = function () { //添加内部代码 }; return my;
} (blogModule || {}));
或
(function (my){
my.AddPhoto = function () { //添加内部代码 }; return my;
})(blogModule || {}));
//调用 blogModule.AddPhoto();
那么,多个自执行函数间是怎么调用的呢?
(function(owner) {
//第一个匿名闭包 owner.debug = true; //Ajax相关参数配置 owner.ajax = { timeout: 10000, type: "post", dataType: "json", };
})(window.C = {}));
如果第二个函数想调用 全局变量为C中的 对象呢?要怎么写?
(function($, owner) {
//这里调用上面全局变量为C 中的对象呢 if(!C.debug) return false; var url = "aaa.html"; mui.ajax({ url: url, dataType: C.ajax.dataType, type: C.ajax.type, });
})(mui, window.app = {});
再举个例子,同样的,不同自执行闭包函数间的调用方法:
(function($, owner) {
//获取语言闭包 owner.getLanguage = function() { var language = localStorage.getItem(C.state.field.language); if(typeof language == "undefined" || language === null || language == "") { var currentLang = navigator.language; if(!currentLang) currentLang = navigator.browserLanguage; language = currentLang.toLowerCase(); language = language.replace(/-/g, "_"); if(language != "en_us" && language != "zh_cn") language = "en_us"; localStorage.setItem(C.state.field.language, language); } //在上面的解析中有说过,Module模式,return 一个变量,这个变量就是要爆露的东西。通过这个函数的全局变量,这个 language 可以在任何地方调用 //return一个变量,其中这个变量里包含你要暴露的东西 //全局调用 storage.language return language; };
})(mui, window.storage = {}));
(function($, owner) {
owner.language = {}; owner.preload = function(settings){ var defaults = { name: "i18n", language: "", path: "/", cache: true, encoding: "UTF-8", autoReplace: true, success: null, error: null, }; settings = $.extend(defaults, settings); if(settings.language === null || settings.language == "") { //全局调用 storage.language settings.language = storage.getLanguage(); } }
})(mui, window.i18n = {});
所以 匿名闭包的调用规则是这样的,立即执行(最后一个括号) (window),如果把window作为一个参数进行传递,那么就把它以对象的方式,在其它函数中实现全局调用。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/96487.html
摘要:在函数内部定义的匿名函数的作用域链中,不包含外部函数的活动对象。在执行完毕以后,其执行环境的作用域链被销毁,但是其活动对象不会被销毁,因为匿名函数的作用域链中仍然引用着这个活动对象,直到匿名函数执行完毕后,才一起被销毁。 函数表达式和函数声明 函数声明:function 函数名称 (参数:可选){ 函数体 } 函数表达式:function 函数名称(可选)(参数:可选){ 函数体 }...
摘要:前言大家学的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行。其实,前面两个例子里的变量,也可以换成,因为和外面的不在一个作用于,所以不会出现问题,这也是匿名函数闭包的威力。 前言 大家学JavaScript的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行。 在详细了解这个之前,我们来谈了解一下自执行这个叫法,本文对这个功能的叫法也不一定完全对...
摘要:总结上面的大部分方式都可以互相组合使用的,一般来说如果要设计系统,可能会用到松耦合扩展,私有状态和子模块这样的方式。 简介 Module模式是JavaScript编程中一个非常通用的模式,一般情况下,大家都知道基本用法,本文尝试着给大家更多该模式的高级使用方式。 首先我们来看看Module模式的基本特征: 模块化,可重用 封装了变量和function,和全局的namaspace不接触...
摘要:第一部分执行代码之后,返回了一个新的匿名函数,此时在全局作用域调用匿名函数它不在是的属性或者方法,此时调用者是因此输出是。总结关于中的,记住谁调用,就指向谁要访问闭包的,要定义个变量缓存下来。 前言: 这是一篇关于闭包函数的总结和笔记 希望对大家有点帮助 写的不好的地方,也请大家多多指教 一: js中的命名函数,匿名函数,自调用函数和回调函数 1.命名函数: 函数如果有名字,就...
摘要:匿名函数是不能单独写的,所以就提不上立即执行了。六立即执行函数在闭包中的应用立即执行函数能配合闭包保存状态。来看下上节内容中闭包的例子现在,我们来利用立即执行函数来简化它第一个匿名函数执行完毕后,返回了第二个匿名函数。 前面的闭包中,提到与闭包相似的立即执行函数,感觉两者还是比较容易弄混吧,严格来说(因为犀牛书和高程对闭包的定义不同),立即执行函数并不属于闭包,它不满足闭包的三个条件。...
阅读 1531·2021-11-18 10:02
阅读 1689·2021-09-04 16:40
阅读 3181·2021-09-01 10:48
阅读 882·2019-08-30 15:55
阅读 1860·2019-08-30 15:55
阅读 1380·2019-08-30 13:05
阅读 3024·2019-08-30 12:52
阅读 1634·2019-08-30 11:24