javascript——四種函數調用形式

  此文的目的是分析函數的四種調用形式,弄清楚函數中this的意義,明確構造函對象的過程,學會使用上下文調用函數。javascript

  在JavaScript中,函數是一等公民,函數在JavaScript中是一個數據類型,而非像C#或 其餘描述性語言那樣僅僅做爲一個模塊來使用. 函數有四種調用模式,分別是:函數調用形式、方法調用形式、構造器形式、以及apply形式. 這裏全部的調用模式中,最主要的區別在於關鍵字 this 的意義. 下面分別介紹這個幾種調用形式.java

 

  1、函數調用形式數組

  函數調用形式是最多見的形式,也是最好理解的形式. 所謂函數形式就是通常聲明函數 後直接調用便是. 例如:瀏覽器

1 //聲明一個函數,而且調用
2 function func(){
3       alert('Hello World!!');      
4 }
5 func();

或者app

1 //使用函數的Lambda表達式定義函數
2 var func = function(){
3      alert("Hello World!!");
4 }
5 func();

  這兩段代碼都會彈出一個對話框,顯示字符串中的文字. 這個就是函數調用。函數

  能夠發現函數調用很簡單,就是平時學習的同樣. 這裏的關鍵是,在函數調用模式中, 函數裏的 this 關鍵字指全局對象,若是在瀏覽器中就是 window 對象. 例如:學習

1 var func = function(){
2        alert(this);  
3 }
4 func();

  此時,會彈出對話框,打印出 [object Window]this

 

  2、方法調用模式spa

  函數調用模式很簡單,是最基本的調用方式. 可是一樣的是函數,將其賦值給一個對象的成員之後,就不同了. 將函數賦值給對象的成員後,那麼這個就不在稱爲函數,而code

應該叫作方法. 例如:

1  // 定義一個函數
2  var func = function() {
3      alert("我是一個函數麼?");
4 };
5  // 將其賦值給一個對象
6  var o = {};
7  o.fn = func; // 注意這裏不要加圓括號
8  // 調用
9  o.fn();

  此時,o.fn 則是方法,不是函數了. 實際上 fn 的方法體與 func 是如出一轍的,可是這裏有個微妙的不一樣. 看下面的代碼:

1  // 接上面的代碼
2 alert(o.fn === func);

打印結果是 true ,這個代表兩個函數是同樣的東西. 可是修改一下函數的代碼:

 1  // 修改函數體
 2 var func = function() {
 3     alert(this);
 4  };
 5  var o = {};
 6  o.fn = func;
 7  // 比較
 8  alert(o.fn === func);
 9  // 調用
10  func();
11  o.fn();

  這裏的運行結果是,兩個函數是相同的,所以打印結果是 true. 可是因爲兩個函數的調用是不同的,func 的調用,打印的是 [object Window],而 o.fn 的打印結果是 [object Object].

  這裏即是函數調用與方法調用的區別. 函數調用中,this 專指全局對象 window,而 在方法中 this 專指當前對象. 即 o.fn 中的 this 指的就是對象 o.

 

  3、構造器調用模式

  一樣是函數,在單純的函數模式下,this 表示 window;在對象方法模式下,this 指的是當前對象. 除了這兩種狀況,javascript 中函數還能夠是構造器. 將函數做爲構造器來使用的語法就是在函數調用前面加上一個 new 關鍵字. 如代碼:

 1 // 定義一個構造函數
 2  var Person = function() {
 3      this.name = "傳智播客";
 4     this.sayHello = function() {
 5      alert("你好,這裏是" + this.name);
 6     };
 7 };
 8  // 調用構造器,建立對象
 9  var p = new Person();
10  // 使用對象
11  p.sayHello();

  上面的案例首先建立一個構造函數Person,而後使用構造函數建立對象p. 這裏使用 new 語法. 而後在使用對象調用sayHello()方法. 這個使用構造函數建立對象的案例比較簡單. 從案例能夠看到,此時 this 指的是對象自己. 

  除了上面簡單的使用之外,函數做爲構造器還有幾個變化. 分別爲:

   一、 全部須要由對象使用的屬性,必須使用 this 引導;

   二、 函數的 return 語句意義被改寫,若是返回非對象,就返回this;

   3.1 構造器中的 this

  咱們須要分析建立對象的過程,方能知道 this 的意義. 以下面代碼:

1 var Person = function() {
2     this.name = "Hello cc!!";
3  };
4  var p = new Person();

  這裏首先定義了函數 Person,下面分析一下整個執行:

  一、 程序在執行到這一句的時候,不會執行函數體,所以javascript 的解釋器並不知道這個函數的內容。

  二、 接下來執行 new 關鍵字,建立對象,解釋器開闢內存,獲得對象的引用,將新對象的引用交給函數。

  三、 緊接着執行函數,將傳過來的對象引用交給 this 也就是說,在構造方法中,this 就是剛剛被 new 建立出來的對象.

  四、 而後爲 this 添加成員,也就是爲對象添加成員. 

  五、 最後函數結束,返回 this, 將 this 交給左邊的變量.

  分析過構造函中數的執行之後,能夠獲得,構造函數的 this 就是當前對象.

  3.2 構造器中的 return

  在構造函數中 return 的意義發生了變化,首先若是在構造函數中,若是返回的是一個對 象,那麼就保留原意. 若是返回的是非對象,好比數字、布爾和字符串,那麼就返回 this,如

果沒有 return 語句,那麼也返回 this. 看下面代碼:

 1  // 返回一個對象的 return
 2  var ctr = function() {
 3      this.name = "cc";
 4      return {
 5         name:"xx"
 6      };
 7 };
 8 // 建立對象
 9  var p = new ctr();
10  // 訪問name屬性
11  alert(p.name);

執行代碼,這裏打印的結果是"xx". 由於構造方法中返回的是一個對象,那麼保留 return的意義,返回內容爲 return 後面的對象. 再看下面代碼:

 1 // 定義返回非對象數據的構造器
 2  var ctr = function() {
 3      this.name = "cc";
 4      return "xx";
 5  };
 6  // 建立對象
 7  var p = new ctr();
 8  // 使用
 9  alert(p);
10  alert(p.name);

代碼運行結果是,先彈窗打印[object Object],而後打印"cc". 由於這裏 return 的是一個字符串,屬於基本類型,那麼這裏的 return 語句無效,返回的是 this 對象. 所以第一個打印的 是[object Object]而第二個不會打印 undefined.

 

4、apply調用模式

  除了上述三種調用模式之外,函數做爲對象還有 apply 方法與 call 方法可使用,這即是 第四種調用模式,我稱其爲 apply 模式. 

  首先介紹 apply 模式,首先這裏 apply 模式既能夠像函數同樣使用,也能夠像方法同樣使用 能夠說是一個靈活的使用方法. 首先看看語法: 函數名.apply(對象, 參數數組);

  這裏看語法比較晦澀,仍是使用案例來講明:

  一、 新建兩個 js 文件,分別爲"js1.js"與"js2.js";

  二、 添加代碼

  三、 分別運行着兩段代碼,能夠發現第一個文件中的 name 屬性已經加載到全局對象 window 中;而第二個文件中的 name 屬性是在傳入的對象 o 中. 即第一個至關於函數調用,第二個至關於方法調用.

 1  // js1.js 文件中
 2  var func1 = function() {
 3      this.name = "Hello cc!!";
 4  };
 5  func1.apply(null);
 6  alert(name); 
 7  // js2.js 文件
 8  var func2 = function() {
 9      this.name = "Hello xx!!";
10  };
11  var o = {};
12  func2.apply(o);
13  alert(o.name);

   這裏的參數是方法自己所帶的參數,可是須要用數組的形式存儲在. 好比代碼:

1 // 一個數組的例子
2  var arr1 = [1,2,3,[4,5],[6,7,8]];
3  // 將其展開
4  var arr2 = arr1.conact.apply([], arr1);

  而後介紹一下 call 模式. call 模式與 apply 模式最大的不一樣在於 call 中的參數不用數組. 看下面代碼就清楚了:

 1  // 定義方法
 2 var func = function(name, age, sex) {
 3      this.name = name;
 4      this.age = age;
 5     this.sex = sex;
 6  };
 7  // 建立對象
 8  var o = {};
 9  // 給對象添加成員
10  // apply 模式
11  var p1 = func.apply(o, ["xx", 25, "男"]);
12  // call 模式
13  var p2 = func.call(o, "xx", 25, "男");

上面的代碼,apply 模式與 call 模式的結果是同樣的.

  實際上,使用 apply 模式和 call 模式,能夠任意的操做控制 this 的意義,在函數 js 的設 計模式中使用普遍. 簡單小結一下,js 中的函數調用有四種模式,分別是:函數式、方法式、構造

器式和 apply 式. 而這些模式中,this 的含義分別爲:在函數中 this 是全局對象 window,在方法中 this 指當前對象,在構造函數中 this 是被建立的對象,在 apply 模式中 this 能夠隨意的

指定. 在 apply 模式中若是使用 null,就是函數模式,若是使用對象,就是方法模式.

相關文章
相關標籤/搜索