AJax技术

使用 Dojo 的 Ajax 应用开发进阶教程,第 1 部分: JavaScript 技巧与高级特性(4)

字号+ 作者:H5之家 来源:H5之家 2017-01-15 12:05 我要评论( )

function addBy(first) { function add(second) {return first + second; } return add; } var func = addBy(10); func(20); // 结果为 30 var newFunc = addBy(30); newFunc(20); // 结果为 50 在 中,外部 functi

function addBy(first) { function add(second) { return first + second; } return add; } var func = addBy(10); func(20); // 结果为 30 var newFunc = addBy(30); newFunc(20); // 结果为 50

在 中,外部 functionaddBy的内部 functionadd的引用被返回给 addBy的调用者,同时 add在方法体中使用了 addBy的参数 first。这样就形成了一个闭包。通过调用 addBy(10)得到的 functionfunc,在其之后的执行过程中,都会保留创建的时候使用的 first参数的值 10。

下面分析 中执行的细节。首先 addBy(10)被调用。由于 addBy是在全局代码中声明的,因此被调用时候的执行上下文对应的作用域链只包含全局对象。在 addBy的方法体中,声明了一个内部 functionadd。add的 [[scope]]属性会在作用域链之前加上 functionaddBy的激活对象。该对象中包含了经过初始化的参数 first,其值为 10。至此,functionfunc的 [[scope]]属性的值是包含两个对象。当 func被调用的时候,会进入一个新的执行上下文,而此时的作用域链的前面加上了 functionadd调用时的激活对象。该对象中包含了经过初始化的参数 second,其值为 20。在 func的执行过程中,需要对两个标识符 first和 second求值的时候,会使用之前提到的包含三个对象的作用域链。从而可以正确的求值。

在 JavaScript 中,正确的使用闭包可以简化代码。下面举几个例子来说明。

避免名称空间冲突

在多人协作开发应用,或是使用第三方开发的 JavaScript 库的时候,一个通常会遇到的问题是名称空间冲突。比如第三方的 JavaScript 库在全局对象中声明了一个属性叫 test,如果在自己的代码中也会声明同样名称的属性的话,当两者一同使用的时候,后加载的属性值会替换之前的值,从而造成错误。

这个时候典型的做法是只在全局对象中保存一个对象,所有的功能都通过引用此对象来完成。完成功能所需要的内部状态都封装在一个闭包中。如 所示。

清单 11. 使用闭包避免名称空间冲突

(function() { if (typeof MyCode === "undefined") { var defaultName = "Alex"; MyCode = { "sayHello" : function(name) { alert("Hello, " + (name || defaultName)); } }; } })(); MyCode.sayHello(); // 输出为 Hello, Alex MyCode.sayHello("Bob"); // 输出为 Hello, Bob

代码中通过创建一个匿名 function 并立即执行来生成一个闭包。在闭包中,通过修改全局对象 MyCode来添加所需的功能。内部状态之一的属性 defaultName被封装在闭包中,不能被闭包之外的代码所引用,也不会引发命名冲突。

保存状态

在 JavaScript 代码运行过程中,不可避免的需要保存一些内部状态。通过使用闭包,可以将内部状态封装在一个 function 内部,使得代码更加简洁。如 所示。

清单 12. 使用闭包保存状态

var getNextId = (function() { var id = 1; return function() { return id++; } })(); getNextId(); // 输出 1 getNextId(); // 输出 2 getNextId(); // 输出 3

代码中的 getNextId的功能是生成惟一的 ID,因此它需要维护当前的 ID 这样一个状态。通过使用闭包,不需要在全局对象中添加一个新的属性,该属性由闭包来维护。闭包之外的代码也不能访问或修改 getNextId的内部状态。

折叠调用参数

在 JavaScript 中,有些 function,如 setTimeout和 setInterval,只接受一个 function 作为参数。在有些情况下,这些 function 的执行是需要额外的参数的。这个时候可以通过使用闭包,将原始 function 的参数进行折叠,得到一个没有参数的新 function 。如 所示。

清单 13. 使用闭包折叠调用参数

function doSomething(a, b, c) { alert(a + b + c); } function fold(a, b, c) { return function() { doSomething(a, b, c); } } var newFunc = fold("Hello", " ", "World"); setTimeout(newFunc, 1000); // 输出为 Hello World

代码中的 doSomething需要三个参数来完成其功能。如果直接将 doSomething传给 setTimeout的话,三个参数的值都是 undefined 。fold将三个参数的值保存在激活对象,并添加在作用域链中。这样即便返回的 function 是没有参数的,它仍然可以获得这三个参数的值。

关于闭包的更多内容,请参见 。

声明

本人所发表的内容仅为个人观点,不代表 IBM 公司立场、战略和观点。

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • jQuery ajax() 方法

    jQuery ajax() 方法

    2017-01-15 13:00

  • AJAX开发技能在PHP开发流程中的基本运用技巧

    AJAX开发技能在PHP开发流程中的基本运用技巧

    2017-01-15 11:01

  • AJAX跨域小结

    AJAX跨域小结

    2017-01-14 15:00

  • Ajax基础教程下载最新版

    Ajax基础教程下载最新版

    2017-01-14 09:02

网友点评
y