JavaScript学习笔记(十三) 返回函数和"自定义"函数

来源:互联网 发布:淘宝店出售转让 编辑:程序博客网 时间:2024/05/16 18:21

返回函数(Returning Functions)

函数是对象,所以它们可以被当做返回值;
这意味着一个函数不一定要返回某种数据或数据的数组作为它的返回值;
一个函数可以返回另一个更加专业的函数,或者依赖于输入返回一个合适的函数;

这里有个例子:一个函数做了一些工作,可能是一些一次性的初始化的工作,然后在返回值上继续工作,返回值恰巧是另外一个函数,可以被执行:
var setup = function() {    alert(1);    return function() {        alert(2);    };};// using the setup functionvar my = setup(); // alerts 1my(); // alerts 2
因为setup()包裹了返回的函数,它创建了一个闭包(closure),所以你可以使用这个闭包去存储一些私有的变量;
这些私有变量是可以被返回的函数访问的,但在这段代码外面就访问不到了;
一个计数器的例子,每次调用都会加1:
var setup = function() {    var count = 0;    return function() {        return (count += 1);    };};// usagevar next = setup();next(); // returns 1next(); // 2next(); // 3

自定义函数(Self-Defining Functions)

函数可以动态的被定义并且可以赋值给变量。
如果你创建了一个新的函数并赋值给一个已经保存着另外一个函数的变量,你会用新的函数覆盖旧的函数;
在某种程度上,你正在回收利用旧的函数指针(引用)指向新的函数,并且所有的这些过程都可以在旧函数的函数体中发生;
在这种情况下,函数被覆盖并且用一个新的实现重新定义它自己;
这听起来可能比实际更难懂,让我们看一个简单的例子:
var scareMe = function() {    alert("Boo!");    scareMe = function() {        alert("Double boo!");    };};// using the self-defining functionscareMe(); // Boo!scareMe(); // Double boo!
这种模式非常有用,当你的函数有一些初始化的准备工作要去做并且只需要做一次(在可以避免的情况下,没有理由去做重复的工作),函数的一部分可能再也不需要了;
在这种情况下,自定义函数可以更新它自己的实现。

使用这种模式可以显著的提高你的程序的性能,因为你重定义的函数会做了更少的工作。

这种模式另外一个名称就是"惰性函数定义(lazy function definition)",因为函数没有被“正确”定义直到第一次被使用的时候,然后它就变懒了,做更少的工作。

这种模式一个缺点就是当它重定义它自己的之后,你给最初的函数添加的任何属性都会丢失;
如果函数和不同的名称一起使用,比如,赋值给不同的变量或者被作为一个对象的方法,那么重定义部分将不会发生并且最初的函数体将会被执行;

让我们来看一个例子,scareMe()函数被当做一个的对象使用:
  1. 添加一个新属性
  2. 函数对象被赋值给新的变量
  3. 函数被当做对象的一个方法
// 1. adding a new propertyscareMe.property = "properly";// 2. assigning to a different namevar prank = scareMe;// 3. using as a methodvar spooky = {    boo: scareMe};// calling with a new nameprank(); // "Boo!"prank(); // "Boo!"console.log(prank.property); // "properly"// calling as a methodspooky.boo(); // "Boo!"spooky.boo(); // "Boo!"console.log(spooky.boo.property); // "properly"// using the self-defined functionscareMe(); // Double boo!scareMe(); // Double boo!console.log(scareMe.property); // undefined
正如你看到的,当函数被赋值给一个新的变量后,你期待的自我定义就不会发生,每一次prank()被调用,会提示"BOO!";
同时,它也会重写全局的scareMe()函数,但prank()它自己看到的仍然还是旧的定义包括property属性;
当调用spooky对象的boo()方法时,也会发生相同的事情,所以这些调用都会重写全局的scareMe()指针;
当scareMe()最后被调用的时候,它的实现已经被更新,所以从一开始就提示”Double boo!“,再也看不到scareMe.property了。