分享

JavaScript 函数是最棒的

 WindySky 2009-07-03
 
关键字: javascript oop

JavaScript 函数是最棒的

在很多编程语言中,函数和对象通常被视为两样不同的东西。在 JavaScript 中,其差别很模糊 — JavaScript 函数实际上是具有与它关联的可执行代码的对象。请如此看待普通函数:

 

Js代码 复制代码
  1. function func(x) {   
  2.     alert(x);   
  3. }   
  4. func(“blah”);  

 这就是通常在 JavaScript 中定义函数的方法。但是,还可以按以下方法定义该函数,您在此创建匿名函数对象,并将它赋给变量 func

Js代码 复制代码
  1. var func = function(x) {   
  2.     alert(x);   
  3. };   
  4. func(“blah2”);  

 甚至也可以象下面这样,使用Function构造函数:

Js代码 复制代码
  1. var func = new Function(“x”, “alert(x);”);   
  2. func(“blah3”);  

Function的第一个参数是函数的入参,第二个参数是函数的主体部分,如果有多个输入参数的写法如下:

Js代码 复制代码
  1. //方法1   
  2. var obj = new Object();   
  3. obj.test = "obj的Test";   
  4.   
  5. var func = new Function   
  6. (   
  7.      ["x","y","z"],    
  8.      "alert(x);alert(y);alert(z.test);"  
  9. );   
  10.   
  11. func("blah1","blah2",obj);  

 

Js代码 复制代码
  1. // 方法2   
  2. var obj = new Object();   
  3. obj.test = "obj的Test";   
  4.   
  5. var func = new Function   
  6. (   
  7.      "x,y,z",    
  8.      "alert(x);alert(y);alert(z.test);"  
  9. );   
  10.   
  11. func("blah1","blah2",obj);  

 

Js代码 复制代码
  1. // 方法3   
  2. var obj = new Object();   
  3. obj.test = "obj的Test";   
  4.   
  5. var func = new Function   
  6. (   
  7.      "x","y",z",    
  8.      "alert(x);alert(y);alert(z.test);"  
  9. );   
  10.   
  11. func("blah1","blah2",obj);  

 

以上三种方法都可以实现定义多个入参的函数。并且演示了如何定义一个入参是对象的函数的定义。

关于Function的小结,如下面代码中的注释:

Js代码 复制代码
  1. /*  
  2.  * Function可以有多个入口参数,最后一个参数最为方法体。  
  3.  */  
  4. var MyObject = new Function("msg","alert(msg);");   
  5.   
  6. var o = new MyObject("Hello world!");  

此示例表明函数实际上只是支持函数调用操作的对象。最后一个使用Function 构造函数来定义函数的方法并不常用,但它展示的可能性非常有趣,因为您可能注意到,该函数的主体正是Function构造函数的String参数。这意味着,您可以在运行时构造任意函数。

为了进一步演示函数是对象,您可以像对其他任何JavaScript对象一样,在函数中设置或添加属性:

Js代码 复制代码
  1. function sayHi(x)   
  2. {   
  3.     alert(“Hi, “ + x + “!”);   
  4. }   
  5. sayHi.text = “Hello World!”;   
  6. sayHi[“text2”] = “Hello World... again.”;   
  7.   
  8. alert(sayHi[“text”]); // displays “Hello World!”  

 作为对象,函数还可以赋给变量、作为其它函数的值返回,并可以作为对象的属性或数组元素进行存储等等。图1提供了这样一个示例。

Figure 1 JavaScript中的函数是最棒的

Js代码 复制代码
  1. // assign an anonymous function to a variable   
  2. var greet = function(x) {   
  3.     alert(“Hello, “ + x);   
  4. };   
  5. greet(“MSDN readers”);   
  6.   
  7. // passing a function as an argument to another   
  8. function square(x) {   
  9.     return x * x;   
  10. }   
  11. function operateOn(num, func) {   
  12.     return func(num);   
  13. }   
  14. // displays 256   
  15. alert(operateOn(16, square));   
  16.   
  17. // functions as return values   
  18. function makeIncrementer() {   
  19.     return function(x) { return x + 1; };   
  20. }   
  21. var inc = makeIncrementer();   
  22. // displays 8   
  23. alert(inc(7));   
  24.   
  25. // functions stored as array elements   
  26. var arr = [];   
  27. arr[0] = function(x) { return x * x; };   
  28. arr[1] = arr[0](2);   
  29. arr[2] = arr[0](arr[1]);   
  30. arr[3] = arr[0](arr[2]);   
  31. // displays 256   
  32. alert(arr[3]);   
  33.   
  34. // functions as object properties   
  35. var obj = { “toString” : function() { return “This is an object.”; } };   
  36. // calls obj.toString()   
  37. alert(obj);  

 记住这一点后,向对象添加方法将是很容易的事情:只需要选择名称,然后将函数赋值给该名称。因此,我通过将匿名函数分别赋值给相应的方法名称,在对象中定义了三个方法:

Js代码 复制代码
  1. var myDog = {   
  2.     “name” : “Spot”,   
  3.     “bark” : function() { alert(“Woof!”); },   
  4.     “displayFullName” : function() {   
  5.         alert(this.name + “ The Alpha Dog”);   
  6.     },   
  7.     “chaseMrPostman” : function() {    
  8.         // implementation beyond the scope of this article    
  9.     }       
  10. };   
  11. myDog.displayFullName();    
  12. myDog.bark(); // Woof!  

 注意myDog.displayFullName(); myDog.bark();调用方法时要加上括号,因为虽然是将方法赋给了对象的属性,但他们还是方法阿。

C++/C# 开发人员应当很熟悉displayFullName 函数中使用的“this”关键字 — 它引用一个对象,通过对象调用方法(使用Visual Basic的开发人员也应当很熟悉它, 它在Visual Basic中叫做“Me”)。因此在上面的示例中,displayFullName中的"this"的值是myDog对象。但是,"this" 的值不是静态的。通过不同对象调用 “this” 时, 它的值也会更改以便指向相应的对象,如图2所示:

 

Figure2 "this" 随对象更改而更改

Js代码 复制代码
  1. <SPAN style="COLOR: #ff0000">function displayQuote() {   
  2.     // the value of “this” will change; depends on    
  3.     // which object it is called through   
  4.     alert(this.memorableQuote);       
  5. }   
  6.   
  7. var williamShakespeare = {   
  8.     'memorableQuote''It is a wise father that knows his own child.',    
  9.     'sayIt' : displayQuote   
  10. };   
  11.   
  12. var markTwain = {   
  13.     'memorableQuote''Golf is a good walk spoiled.',    
  14.     'sayIt' : displayQuote   
  15. };   
  16.   
  17. var oscarWilde = {   
  18.     'memorableQuote''True friends stab you in the front.'    
  19.     // we can call the function displayQuote   
  20.     // as a method of oscarWilde without assigning it    
  21.     // as oscarWilde’s method.    
  22.     //”sayIt” : displayQuote   
  23. };   
  24.   
  25. williamShakespeare.sayIt(); // true, true   
  26. markTwain.sayIt(); // he didn’t know where to play golf   
  27.   
  28. // watch this, each function has a method call()   
  29. // that allows the function to be called as a    
  30. // method of the object passed to call() as an   
  31. // argument.    
  32. // this line below is equivalent to assigning   
  33. // displayQuote to sayIt, and calling oscarWilde.sayIt().   
  34. displayQuote.call(oscarWilde); // ouch!   
  35. // oscarWilde.displayQuote();    
  36. // 这么写则会抛出异常(IE:对象不支持此属性或方法)   
  37. // 由此可以看到call函数的强大。</SPAN>  

 

图2中的最后一行表示的是将函数作为对象的方法调用的另一种方式。 请记住,JavaScript中的函数是对象。每个函数对象都有一个名为call的方法,它将函数(displayQuote)作为第一个参数(oscarWilde)的方法进行调用。就是说,作为函数第一个参数传递给call的任何对象都将在函数调用中成为 "this" 的值。这一技术对于调用基类构造函数来说非常有用,稍后将对此进行介绍。

注意在williamShakespeare和markTwain对象中,将displayQuote()函数赋给了这两个对象,而并没有将它赋给oscarWilde对象,williamShakespeare和markTwain对象调用displayQuote()函数如果还比较好理解的话,那么oscarWilde对象调用displayQuote()函数就比较难于理解了。

call()方法只是让oscarWilde对象调用displayQuote()方法,并没有将displayQuote()作为一个属性赋给oscarWilde对象。这与
var markTwain =
{
    'memorableQuote': 'Golf is a good walk spoiled.',
    'sayIt' : displayQuote
};
有着明显的不同。后者是使displayQuote方法称为对象的成员之一,而call不是,它只是调用。我们看到
// oscarWilde.displayQuote();
displayQuote.call(oscarWilde); // ouch!
// oscarWilde.displayQuote();
// 这么写则会抛出异常(IE:对象不支持此属性或方法)
oscarWilde.displayQuote();这一句不论放在call方法前还是放在call方法后执行都会抛异常。
 

有一点需要记住,绝不要调用包含"this"(却没有所属对象)的函数。否则,将违反全局命名空间,因为在该调用中,"this" 将引用全局对象,而这必然会给您的应用程序带来灾难。例如,下面的脚本将更改JavaScript的全局函数 isNaN 的行为。一定不要这样做!

Js代码 复制代码
  1. alert(“NaN is NaN: “ + isNaN(NaN));   
  2. function x() {   
  3.     this.isNaN = function() {    
  4.         return “not anymore!”;   
  5.     };   
  6. }   
  7. // alert!!! trampling the Global object!!!   
  8. x();   
  9.   
  10. alert(“NaN is NaN: “ + isNaN(NaN));  

 注意:isNaN()是JavaScript的一个全局函数,运行上面的程序可以看到,两次执行isNaN(NaN)结果是不一样的,这是因为执行x()函数时,x()函数中的"this"并没有指向某一个对象,这是"this"指向全局函数,则x()将i全局函数sNaN()的实现修改了。

到这里,我们已经介绍了如何创建对象,包括它的属性和方法。但如果注意上面的所有代码段,您就会发现属性和方法是在对象定义本身中进行硬编码的。但如果需要更好地控制对象的创建,该怎么办呢?例如,您可能需要根据某些参数来计算对象的属性值。或者,可能需要将对象的属性初始化为仅在运行时才能获得的值。也可能需要创建对象的多个实例(此要求非常常见)。

 

在C#中,我们使用类来实例化对象实例。但是JavaScript与此不同,因为它没有类。您将在下一节中看到,您可以充分利用这一情况:函数在于"new"运算符一起使用时,函数将充当构造函数。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多