【轉】函數的四種調用方式
函數的四種調用模式
在 js 中 不管是函數, 仍是方法, 仍是事件, 仍是構造器, ... 其本質都是函數. 只是處在不一樣的位子而已.html
四種:數組
- 函數模式
- 方法模式
- 構造器模式
- 上下文模式
函數模式
特徵: 就是一個簡單的函數調用. 函數名的前面沒有任何引導內容.瀏覽器
function foo () {} var func = function () {}; ... foo(); func(); (function (){})();
this 的含義: 在 函數中 this 表示全局對象, 在瀏覽器中是 windowmarkdown
方法模式
特徵: 方法必定是依附於一個對象, 將函數賦值給對象的一個屬性, 那麼就成爲了方法.app
function f() { this.method = function () {}; } var o = { method: function () {} }
this 的含義: 這個依附的對象.函數
構造器調用模式
建立對象的時候 構造函數作了什麼?post
因爲構造函數只是給 this 添加成員. 沒有作其餘事情. 而方法也能夠完成這個操做, 就 this 而言,
構造函數與方法沒有本質區別.this
特徵:url
- 使用 new 關鍵字, 來引導構造函數.
- 構造函數中發 this 與方法中同樣, 表示對象, 可是構造函數中的對象是剛剛建立出來的對象
- 構造函數中不須要 return, 就會默認的 return this
補充:prototype
- 若是手動的添加 return, 就至關於 return this
- 若是手動的添加 return 基本類型; 無效, 仍是保留原來 返回 this
- 若是手動添加 return null; 或 return undefiend, 無效
- 若是手動添加 return 對象類型; 那麼原來建立的 this 就會被丟掉, 返回的是 return 後面的對象
建立對象的模式
-
工廠方法
// 工廠就是用來生產的, 所以若是函數建立對象並返回, 就稱該函數爲工廠函數 function createPerson( name, age, gender ) { var o = {}; o.name = name; o.age = age; o.gender = gender; return o; } // document.createElement()
- 構造方法
-
寄生式建立對象
// 外表看起來就是構造方法, 可是本質不是的構造方法建立對象的方式 function createPerson( name, age, gender ) { var o = {}; o.name = name; o.age = age; o.gender = gender; return o; } var p = new createPerson( 'jim', 19, 'male' );
-
混合式建立
上下文調用模型
上下文 就是環境, 就是自定義設置 this 的含義
語法:
- 函數名.apply( 對象, [ 參數 ] );
- 函數名.call( 對象, 參數 );
描述:
- 函數名就是表示的函數自己, 使用函數進行調用的時候默認 this 是全局變量
- 函數名也能夠是方法提供, 使用方法調用的時候, this 是指當前對象.
- 使用 apply 進行調用後, 不管是函數, 仍是方法都無效了. 咱們的 this, 由 apply 的第一個參數決定
注意:
- 若是函數或方法中沒有 this 的操做, 那麼不管什麼調用其實都同樣.
- 若是是函數調用 foo(), 那麼有點像 foo.apply( window ).
- 若是是方法調用 o.method(), 那麼有點像 o.method.apply( o ).
參數問題
不管是 call 仍是 apply 在沒有後面的參數的狀況下( 函數無參數, 方法無參數 ) 是徹底同樣的.
function foo() { console.log( this ); } foo.apply( obj ); foo.call( obj );
第一個參數的使用也是有規則的
- 若是傳入的是一個對象, 那麼就至關於設置該函數中的 this 爲參數
-
若是不傳入參數, 或傳入 null. undefiend 等, 那麼至關於 this 默認爲 window
foo(); foo.apply(); foo.apply( null ); foo.call( undefined );
- 若是傳入的是基本類型, 那麼 this 就是基本類型對應的包裝類型的引用
- number -> Number
- boolean -> Boolean
- string -> String
除了 this 的參數外的參數
在使用 上下文調用的 時候, 原函數(方法)可能會帶有參數, 那麼這個參數在上下文調用中使用 第二個( 第 n 個 )參數來表示
function foo( num ) { console.log( num ); } foo.apply( null, [ 123 ] ); // 等價於 foo( 123 );
應用
上下文調用只是能修改 this, 可是使用的最多的地方上是借用函數調用.
將僞數組轉換爲數組
傳統的作法
var a = {}; a[ 0 ] = 'a'; a[ 1 ] = 'b'; a.length = 2; // 數組自帶的方法 concat // 語法: arr.concat( 1, 2, 3, [ 4, [ 5 ] ] ); // 特色不修改原數組 var arr = []; var newArr = arr.concat( a );
因爲 a 是僞數組, 只是長得像數組. 因此這裏不行, 可是 apply 方法有一個特性, 能夠將數組或僞數組做爲參數
foo.apply( obj, 僞數組 ); // IE8 不支持
將 a 做爲 apply 的第二個參數
var newArr = Array.prototype.concat.apply( [], a )
處理數組轉換, 實際上就是將元素一個一個的取出來構成一個新數組, 凡是涉及到該操做的方法理論上均可以
- push, unshift
- slice
- splice
push 方法
用法: arr.push( 1 ); 將這個元素加到數組中, 並返回所加元素的個數 arr.push( 1, 2, 3 ); 將這三個元素依次加到數組中, 返回所加個數 var a = { length: 0 }; // 僞數組 a[ a.length++ ] = 'abc'; // a[ 0 ] = 'abc'; a.length++; a[ a.length++ ] = 'def'; // 使用一個空數組, 將元素一個個放到數組中便可 var arr = []; arr.push( a ); // 此時不會將元素展開, 而是將這個僞數組做爲一個元素加到數組中 // 再次利用 apply 能夠展開僞數組的特徵 arr.push.apply( arr, a ); // 利用 apply 能夠展開僞數組的特性, 這裏就至關於 arr.push( a[0], a[1] )
slice
語法: arr.slice( index, endIndex ) 若是第二個參數不傳, 那麼就是 從 index 一致獲取到結尾 該方法不會修改原數組 var a = { length: 0 }; a[ a.length++ ] = 'abc'; a[ a.length++ ] = 'def'; // 假設他是一個數組, 就是應該 從 0 項開始截取到 最後 // 若是能夠的話, 應該 a.slice( 0 ) // 可是他沒有該方法 // 借用 數組的 slice, 將 this 轉換成 這個僞數組 var arr = []; var newArr = arr.slice.apply( a, [ 0 ] );