理解javascript函数的关键就是抛弃主流面向对象语言中“类”的观念。

主流的面向对象语言,例如C++,先写好“类”的定义。当需要对象时,用new关键字去划出一片内存来,赋上初值,就有了一个对象(“类”的“实例”)。混淆的来源是javascript语言模仿了面向对象的语法,看到Object,new之类的关键字,很难不让人去联想那些传统的面向对象的经典概念。

我们可以优雅的模仿“类”的观念,但是始终要提醒自己,javascript只有对象,没有类。

 
  
  1. //Animal是一个对象  
  2. Animal = {  
  3.     createNew: function( bundle ) {  
  4.         var animal = {};  
  5.         var protect = bundle || {};//bundle传递的是指针,修改protect时外面对象会跟着变(除非不传)  
  6.         protect.sound = 'growl';  
  7.         protect.makeSound = function(){   
  8.             return protect.sound;   
  9.         }  
  10.         return animal;  
  11.     }  
  12. }  
  13.  
  14. //Cat也是一个对象  
  15. Cat = {  
  16.     createNew: function(mySound) {  
  17.         var protect = {};  
  18.         var cat = Animal.createNew( protect );//protect会被修改,然后返回空白对象{}给cat  
  19.         protect.sound = mySound;  
  20.         cat.meow = function(){ return protect.makeSound(); };//cat要调用protect中的方法  
  21.         return cat;  
  22.     }  
  23. }  
  24.    
  25. //javascript区分大小写,通过Cat对象构造一个新的对象赋值给cat  
  26. var cat = Cat.createNew("meow!");  
  27. pt("cat.sound");//cat不能直接访问sound  
  28. pt("cat.meow()");//通过函数可以访问sound  
  29. var bigCat = Cat.createNew("meow!meow!meow!");  
  30. pt("bigCat.sound");//bigCat也不能直接访问sound  
  31. pt("bigCat.meow()");//通过函数可以访问sound  

调试信息: 
cat.sound undefined
cat.meow() meow!
bigCat.sound undefined
bigCat.meow() meow!meow!meow!
[备注] 如果希望大猫(bigCat)小猫(cat)有公共的属性,因为Cat本身也是一个对象,所以可以在Cat中定义对象作为公共属性,并在createNew中增加操纵此公共属性的函数。

模仿“类”的观念让我联想到了东施效颦的典故。东施模仿西施优雅的举止肯定是不能达到西施的水准,但是东施难道就没有自己的特长么?例如,做家务会不会比西施更能干呢?javascript函数最大的好处就是可以赋值给变量,因而我们可以编写“函数的函数”,或者,把函数当参数传来传去,函数也可以有自己的方法,诸如此类。还记得在学习早期结构化的编程语言(例如Fortran和C)时,被纠正说不能传递函数当参数么?

 
  
  1. Function.prototype.run=function(){  
  2.     return "run~~";  
  3. }  
  4. pt("cat.meow.run()");//函数也可以有方法 

 调试信息: 
cat.meow.run() run~~

下面玩一个克隆函数的小把戏:

 
  
  1. //有此方法今后不需要再写prototype关键字  
  2. Function.prototype.method = function(name,func){  
  3.     this.prototype[name] = func;  
  4.     return this;  
  5. };  
  6. //添加cloneFunction方法  
  7. Function.method("cloneFunction",function(){  
  8.     var slice = Array.prototype.slice;  
  9.     var args = slice.apply(arguments);  
  10.     var that = this;  
  11.     return function(){  
  12.         return that.apply(null,args.concat(slice.apply(arguments)));//此处slice.apply(arguments)含义与前处不同  
  13.     }});  
  14. //定义add函数  
  15. var add = function(a,n){  
  16.         return a+n;  
  17. }  
  18.  
  19. pt("add(0,5)");//调试输出  
  20.  
  21. var add1 = add.cloneFunction(1);//克隆1  
  22. var add2 = add.cloneFunction(2);//克隆2  
  23. var add3 = add.cloneFunction(3);//克隆3  
  24.  
  25. pt("add1(5)");//调试输出  
  26. pt("add2(5)");//调试输出  
  27. pt("add3(5)");//调试输出  

调试信息: 
add(0,5) 5
add1(5) 6
add2(5) 7
add3(5) 8

想获得全部可执行代码,请下载附件。