函數的四種調用方式


函數的四種調用模式

在 js 中 無論是函數, 還是方法, 還是事件, 還是構造器, ... 其本質都是函數. 只是處在不同的位子而已.

四種:

  1. 函數模式
  2. 方法模式
  3. 構造器模式
  4. 上下文模式

函數模式

特征: 就是一個簡單的函數調用. 函數名的前面沒有任何引導內容.

	function foo () {}
	var func = function () {};
	...
	
	foo();
	func();
	(function (){})();

this 的含義: 在 函數中 this 表示全局對象, 在瀏覽器中是 window

方法模式

特征: 方法一定是依附於一個對象, 將函數賦值給對象的一個屬性, 那么就成為了方法.

	function f() {
		this.method = function () {};
	}
	var o = {
		method: function () {} 
	}

this 的含義: 這個依附的對象.

構造器調用模式

創建對象的時候 構造函數做了什么?

由於構造函數只是給 this 添加成員. 沒有做其他事情. 而方法也可以完成這個操作, 就 this 而言,
構造函數與方法沒有本質區別.

特征:

  1. 使用 new 關鍵字, 來引導構造函數.
  2. 構造函數中發 this 與方法中一樣, 表示對象, 但是構造函數中的對象是剛剛創建出來的對象
  3. 構造函數中不需要 return, 就會默認的 return this

補充:

  1. 如果手動的添加 return, 就相當於 return this
  2. 如果手動的添加 return 基本類型; 無效, 還是保留原來 返回 this
  3. 如果手動添加 return null; 或 return undefiend, 無效
  4. 如果手動添加 return 對象類型; 那么原來創建的 this 就會被丟掉, 返回的是 return 后面的對象

創建對象的模式

  1. 工廠方法
	// 工廠就是用來生產的, 因此如果函數創建對象並返回, 就稱該函數為工廠函數
	function createPerson( name, age, gender ) {
		var o = {};
		o.name = name;
		o.age = age;
		o.gender = gender;
		return o;
	}
	
	// document.createElement() 
  1. 構造方法
  2. 寄生式創建對象
	// 外表看起來就是構造方法, 但是本質不是的構造方法創建對象的方式
	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' );
  1. 混合式創建

上下文調用模型

上下文 就是環境, 就是自定義設置 this 的含義

語法:

  1. 函數名.apply( 對象, [ 參數 ] );
  2. 函數名.call( 對象, 參數 );

描述:

  1. 函數名就是表示的函數本身, 使用函數進行調用的時候默認 this 是全局變量
  2. 函數名也可以是方法提供, 使用方法調用的時候, this 是指當前對象.
  3. 使用 apply 進行調用后, 無論是函數, 還是方法都無效了. 我們的 this, 由 apply 的第一個參數決定

注意:

  1. 如果函數或方法中沒有 this 的操作, 那么無論什么調用其實都一樣.
  2. 如果是函數調用 foo(), 那么有點像 foo.apply( window ).
  3. 如果是方法調用 o.method(), 那么有點像 o.method.apply( o ).

參數問題

無論是 call 還是 apply 在沒有后面的參數的情況下( 函數無參數, 方法無參數 ) 是完全一樣的.

	function foo() {
		console.log( this );
	}
	foo.apply( obj );
	foo.call( obj );

第一個參數的使用也是有規則的

  1. 如果傳入的是一個對象, 那么就相當於設置該函數中的 this 為參數
  2. 如果不傳入參數, 或傳入 null. undefiend 等, 那么相當於 this 默認為 window
	foo();
	foo.apply();
	foo.apply( null );
	foo.call( undefined );
  1. 如果傳入的是基本類型, 那么 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 )

處理數組轉換, 實際上就是將元素一個一個的取出來構成一個新數組, 凡是涉及到該操作的方法理論上都可以

  1. push, unshift
  2. slice
  3. 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 ] );


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM