Javascript 函數初探

來源:互聯網
上載者:User


      在 Javascript 中, 函數是“一等公民”, 它是 Javascript 的中心對象。

       1.  函數是值,可以用在值被用到的任何地方。 可以儲存在變數中, 用於運算式中,放在數組裡, 放在對象的值對裡, 作為參數傳入函數, 作為函數傳回值;
       2.  函數是對象, 可以擁有資料屬性, 擁有方法, 指向原型對象;
       3.  函數擁有可調用的代碼塊,有多種調用模式; 可以製造閉包和回調, 這兩種編程模式是非常強大的。

       代碼運行:  開啟 chrome 瀏覽器, 工具 --- Javascript 控制台。 

       參考文獻:  
          
           《Javascript: The Good Parts》 Douglas Crockford
       

       一.   函數是值 

       讓我們從最常規的函數調用形式開始吧! 


       1.  函數儲存在變數中。

       先看一段普通的代碼: 

       function numAdd(a,b) {
             return a+b;
       } 
       numAdd(5, 7);

       實際上,它的含義是:

       var numAdd = function(a,b) {
             return a+b;
       }
       numAdd(5, 7);

       函數對象被儲存在變數 numAdd 中, 可以通過該變數進行引用;

       2.  函數用於運算式中

       var  choice =  function(boolvar) {
              return  boolvar ?  function(num) { return num*num }  :  function(num) {  return num / 2; }
       }   
       var  square = choice(true);
       square(2);   // print 4
       var  half = choice(false);
       half(4);       //  print 2     
      
       這段代碼根據傳入的布爾值, 分別返回不同的函數對象; 如果為真, 則返回平方值函數, 如果為假,則返回取半函數。 它也示範了函數如何作為傳回值。

      3.  函數作為參數傳入函數

      var worker = function(callback) {
          var arrparams = [1, 2, 3, 4, 5];  
          callback(arrparams);
      };
      worker(function(arrparams) {
            document.write('You get me print it !');
            document.write(arrparams.join(' '));
      });
      worker(function(arrparams) {
            document.write('You get me print it reversed !');
            var reversed = arrparams.reverse();
            document.write(reversed.join(' '));
      });

      函數作為參數傳入函數, 可以演變成回調。 回調是一種非常強大的編程模式。回調請參考文章 《編程模式:回調》

      4.  函數作為對象的值對

      var person = { 
              name : 'Shuqin',
              say :  function() {
                    document.write("I am " + this.name);
              }  
       }
       person.say();

      上述代碼示範了 Javascript 中的對象封裝基本方法。

      
       二、 函數是對象

       對象擁有資料屬性, 擁有方法, 擁有原型對象。 函數的原型對象是 Function.prototype .  繼續前面的例子:

       worker.salary = '6K';
       document.write("My salary is " + worker.salary);     

       document.write("My type is " + worker.typename);  
       Function.prototype.typename =  'func';   // 將所有函數的 typename 屬性設定為 func 
       document.write("My type is " + worker.typename);  
       document.write("My type is " + choice.typename);  
         
       Function.prototype.fsay = function() {   // 為所有函數添加 fsay 方法
              document.write('Hey, i am a function, the first class object in javascript');
       }
       worker.fsay();
       choice.fsay();

       worker.mycareer = function(career) {   // 僅為 worker 函數添加方法
              document.write('I am worker ' + career);
       }
       worker.mycareer(' a programmer');
       choice.mycareer(' a choice');   // Error: Has no method 'mycareer'

      基於原型的繼承機制的最大優點就是動態靈活, 可以在運行時動態地添加任何屬性和方法。 當然, 過度濫用會導致混亂。     

      三、 閉包

      函數可以嵌套在另一函數中, 內層函數可以訪問外層函數的私人變數,從而延伸了其範圍。

        var secretMan = function() {
            var count = 1;
            var secret = 'very very important secret.  Poison case happened in tsinghua 19 years ago';
            return function() {
                  count +=1;
                  return secret + " ********* " + count;    
            }
      }
      document.write("The secret: " + secret);  //Error: ReferenceError: secret is not defined
      var revealTruth = secretMan();
      document.write('Now is the time to reveal it out: ' + revealTruth());
      // 頁面列印: Now is the time to reveal it out: very very important secret. Poison case happened in tsinghua 19 years ago ********* 2
      document.write('Now is the time to reveal it out: ' + revealTruth());
      // 頁面列印: Now is the time to reveal it out: very very important secret. Poison case happened in tsinghua 19 years ago ********* 3


      注意到, 當執行完 var revealTruth = secretMan() 之後, 作為局部變數的 count,  secret 均應該退出其範圍(退出參數棧而不存), 但由於內層函數的存在,它們依然存在著並可以繼續使用, 例如 在 第二遍 revealTruth() 調用時依然可以訪問 count 的值。

      四、 調用模式與 this

      函數有四種調用模式: 通過變數引用, 通過對象方法, 通過構造器, 通過 apply 函數.

         1.  變數引用: 將函數Object Storage Service在變數中, 從而通過變數引用來調用。 this 綁定在全域對象中;
         2.  對象方法: 函數作為對象方法而調用, this 動態綁定給當前調用函數的對象; 綁定發生在調用時;
         3.  構造器: 函數用於建立和初始化新對象,  this 綁定給新建立的對象;
         4.  apply :   函數作為參數傳入 apply 函數, this 綁定給指定的對象。 

         第一種情況:
         var outer = function() {
               document.write('Outer this: ' + this);     // [object Window]
               var inner = function() {
                    document.write('Inner this: ' + this);  // [object Window]
                };
                inner();
         }
         outer();

         第二種情況:      
         var person = { 
              name : 'Shuqin',
              sayme :  function() {
                    document.write("Object this: " + this.name);   // Shuqin
                    ( function() {
                           document.write('Inner this: ' + this);  // [object Window] , this 被切換了!
                     })();
              }  
       }
       person.sayme();     

      第三種情況:
      var Man =  function(name, power) {
              this.name =  name;   // this 綁定到將要被建立的新對象
              this.sex = 'Man';
              this.power = power;
              this.ability = function() {
                    document.write('Name: ' + this.name + 'Sex: ' + this.sex + 'Power: ' + this.power);
                    if (this.power < 80) {
                         document.write('Oh, no , you power is little, you must strengthen it!');
                    }
              }
       }  
       var me = new Man('Shuqin', 60);
       me.ability();

       第四種情況:      
       var  generalsum = function(callback, args) {
              document.write("generalsum this: " + this);
              var result = 0;
              var caller ;
              if (typeof this == 'function') {  
                    caller = this;  
              }
              else {
                    caller = callback;
               }
               document.write((typeof caller) + ' ' + args.join(' '))
               for (i=0; i < args.length; i++) {
                    result += caller(args[i]);
                     document.write(result);
               }
               return result; 
        };      
        var plainsumdef = function(num) { return num; } 
        generalsum(plainsumdef, [1, 2, 3, 4, 5]);   // this: [object Window]
        var plainsum = generalsum.apply(plainsumdef, [null, [1,2,3,4,5]]);  // this: function (num) { return num; }

        在這種情況下, this 被綁定到指定對象。

         

        小結

        本文初步探討了 Javascript 的函數,所給例子傾向於闡明它的基本特徵。在實際中, 還需要深入去使用它, 衍化出各種進階技巧。 理解它, 將成為理解 javascript 的一把鑰匙。
 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.