JavaScript 學習筆記 之 原生函數

原生函數是什麼

JavaScript的原生函數也叫內建函數

例如 String(),Number(),Boolean()等

原生函數可以被當做構造函數來使用

但通過構造函數(如new String("abc"))創建出來的是封裝了基本類型值("abc")的封裝對象

		var abc = new String("abc");
		console.log(typeof abc); //object 不是string

[[class]]

[[class]]是所有typeof返回值爲"object"的對象的一個內部屬性(函數的typeof返回值爲"function"),這個屬性無法被直接訪問

但可以通過Object.prototype.toString(..)來查看,可以把它看做是一個內部的分類

		Object.prototype.toString.call(abc);//[object String]

多數情況下,對象內部的[[class]]屬性和創建改對象的內建原生構造函數相對應

		Object.prototype.toString.call([1, 2, 3]); //[object Array]

但並非總是如此

		Object.prototype.toString.call(undefined); //[object Undefined]

可以看到undefined不存在Undefined()這樣的原生構造函數,但是[[class]]仍然是"Undefined"(null的[[class]]是"Null")

而其他的基本類型則存在一個被稱爲包裝(boxing)的行爲

		Object.prototype.toString.call("123"); //[object String]
		Object.prototype.toString.call(123); //[object Number]
		Object.prototype.toString.call(true); //[object Boolean]

上例中基本類型被各自的封裝對象自動包裝,所以它們的內部[[Class]]值分別爲"String","Number","Boolean"

 

封裝對象包裝

由於基本類型沒有.length這樣的屬性和.toString()這樣的方法

需要通過封裝對象才能訪問,此時JavaScript會自動爲基本類型值包裝(box或者wrap)一個封裝對象

		var a = "abc";
		a.length; //3

想要自行封裝基本類型值可以用Object(..)函數(不加new)

拆封

由於封裝對象是一個對象,所以不管基本類型值是什麼,進行判斷的時候返回的都是一個真值

當我們需要得到封裝對象中的基本類型值時,可以用valueOf(..)函數

		var a = Object("abc");
		console.log(a.valueOf());//abc

在需要用到封裝函數中的基本類型值的時候會發生隱式解封

		var a = Object("abc");
		var b = a + "";
		console.log(b, typeof b); //abc string

 

原生函數作爲構造函數

使用Array(..)構造一個數組和直接聲明一個數組的效果是一樣的,創建的值都是通過封裝對象來包裝

使用Array(..)構造函數時候帶new和不帶new效果是一樣的,不帶new的時候會自動補上

只帶一個數字參數的時候,該參數會被當做預設長度,而不是當做數組中的一個元素

如果一個數組沒有任何單元,但是length屬性卻顯示有,這樣會出現空單元的情況

		var a = new Array(3);
		console.log(a); //(3) [empty × 3]

我們將包含至少一個空單元的數組稱之爲稀疏數組

在某些方法中空單元的行爲和undefined類似,但在另一些方法中又完全不同

		var a = new Array(3);
		var b = [undefined, undefined, undefined];
		console.log(a); //(3) [empty × 3]
		console.log(b); //(3) [undefined, undefined, undefined]
		console.log(
			a.join("-"), //--
			b.join("-") //--
		);
		console.log(
			a.map(function(value, index) {
				return index;
			}), //(3) [empty × 3] 
			b.map(function(value, index) {
				return index;
			}) //(3) [0, 1, 2]
		);

這是因爲join方法會先假定數組不爲空,然後通過length來遍歷

而map方法則不會

由於空單元存在的種種問題,因此我們不建議在任何情況下創建和使用空單元

我們可以用另一種方法來更安全創建undefined值的數組

		var a = Array.apply(null, {
			length: 3
		});
		console.log(a); //(3) [undefined, undefined, undefined]

Array.apply把{length:3}作爲參數調用Array()方法

在傳入參數時假設apply有個for循環來遍歷傳入的類數組對象

從0開始循環到length

但是由於傳入的類數組對象中並沒有[0],[1],[2]等屬性,於是返回的是undefined

因此實際上執行的就變成了Array(undefined,undefined,undefined)

 

原生函數的原型

原生構造函數也有自己的.prototype對象,如Array.prototype

這些對象包含其子對象所特有的行爲特徵

比如String.prototype.indexOf(..)

根據文檔約定,這類方法一般簡寫爲String#indexOf(..)

 

而原生的函數的原型同樣也是不錯的默認值

因爲類似於Array.prototype已經被創建過一次了

如果將默認值設定爲 [] 的話會導致資源的浪費,因爲每次使用都需要創建一次

但是如果默認值隨後會改變的話,就不要使用這種方法

因爲修改原型會導致很多問題

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章