紅寶書《JavaScript高級程序設計》學習筆記(五)引用類型

目錄

 

5.1 Object類型

5.2 Array類型

5.3 Date類型

5.4 RegExp類型

5.5 Function類型

5.6 基本包裝類型

5.7 單體內置對象


5.1 Object類型

創建Object實例的方法有兩種

(1)使用new操作符後跟Object構造函數

var person = new Object();
person.name = "Nicholas"; 
person.age = 29;

(2)對象字面量表示法

var person = {
name : "Nicholas", 
age : 29
};

在使用字面量語法時,屬性名也可以使用字符串。也可以使用數字,但數字會自動轉化爲字符串。

 

let person ={};//與new Object();相同

實際上,對象字面量也是向函數傳遞大量可選參數的首選方式。

對於對象的屬性,可以用“對象.屬性”的形式,也可以用“對象[屬性]”的形式,二者從功能上沒有任何區別,但方括號語法可以通過變量訪問屬性,或者屬性名含有空格時,方括號表示法能完美勝任。通常,除非必須使用變量訪問屬性,否則建議使用點表示法

//變量
var propertyName = "name"; 
alert(person[propertyName]); //"Nicholas"


//變量含有空格
person["first name"] = "Nicholas";

5.2 Array類型

ECMAScript中的數組的大小是可以動態調整的,即可以隨着數據的添加自動增長以容納新增數據。

var colors = new Array();//Array構造函數
var colors = new Array(20);//定長
var colors = new Array("red", "blue", "green");//直接傳入字符串

在使用Array構造函數時也可以省略new操作符。

創建數組的第二種基本方式是使用數組字面量表示法。數組字面量由一對包含數組項的方括號表示,多個數組項之間以逗號隔開。

var colors = ["red", "blue", "green"]; // 定義一個字符串數組
alert(colors[0]); // 顯示第一項 
colors[2] = "black"; // 修改第三項
colors[3] = "brown";// 新增第四項

如果設置某個值的索引超過了數組現有項數,如這個例子中的 colors[3]所示,數組就會自動增加到該索引 值加 1 的長度(就這個例子而言,索引是 3,因此數組長度就是 4)。

數組的 length 屬性很有特點——它不是隻讀的。因此,通過設置這個屬性,可以從數組的末尾移除項或向數組中添加新項。

var colors = ["red", "blue", "green"]; // 創建一個包含 3 個字符串的數組 
colors.length = 2;
alert(colors[2]); //undefined

 這個例子中的數組 colors 一開始有 3 個值。將其 length 屬性設置爲 2 會移除最後一項(位置爲 2 的那一項),結果再訪問 colors[2]就會顯示 undefined 了。如果將其 length 屬性設置爲大於數組項數的值,則新增的每一項都會取得 undefined 值。

利用length屬性可以很方便地在數組末尾添加新項。

var colors = ["red", "blue", "green"];// 創建一個包含 3 個字符串的數組
colors[colors.length] = "black"; //(在位置3)添加一種顏色
colors[colors.length] = "brown"; //(在位置4)再添加一種顏色

 

Array.isArray()用來確定某個對象是不是數組。

數組使用toString()會返回由數組每個值拼接而成的一個以逗號分割的字符串。valueOf()則爲了創建這個字符串會調用數組每一項的toString()方法。雖然toLocaleString()也經常返回和前兩個方法相同的值,但也不盡然。它調用的是每一項的toLocaleString()方法,而不是toString()方法。

var colors = ["red", "blue", "green"]; // 創建一個包含 3 個字符串的數組
alert(colors.toString()); // red,blue,green
alert(colors.valueOf()); // red,blue,green
alert(colors);// red,blue,green

如果使用 join()方法,則可以使用不同的分隔符來構建這個字符串。join()方法只接收一個參數,即用作分隔符的字符串,然後返回包含所有數組項的字符串。

var colors = ["red", "green", "blue"]; 
alert(colors.join(",")); //red,green,blue 
alert(colors.join("||")); //red||green||blue

 

push()方法接收任意參數逐個添加到數組末尾,並修改數組的長度。pop()方法則從數組末尾移除最後一項。用這兩個方法可以模擬出棧和入棧

shift()方法移除數組第一項。利用shift()和push()可以像隊列一樣使用數組。

ECMAScript還爲數組提供了unshift()方法在數組首部添加項,並返回新的長度。

 

reverse()方法會反轉數組項的順序。

sort()會按照升序排列數組項。sort()方法比較的是字符串,所以用sort()比較數字的時候要傳入一個“比較函數”保證正確的升序。sort(比較函數);比較函數返回1表示“前值要放在後值後”,返回-1要表示“前值要放在後值之前”。

//比較函數
let compare=(value1,value2)=>{
    return value2-value1;
}

 

concat()基於當前數組的所有項創建一個新數組(延長數組)。

slice()基於當前數組的一或多個項創建新數組(截取數組)。可以接收一或兩個參數,即要返回項的起始和結束位置。

 

splice()可以傳入兩個以上的參數,第一個是要刪除的位置,第二個是要刪除的項數,後面可以插入任意數量的參數,用於插入任意數量的項。通過這些參數可以實現刪除、插入、替換。splice()方法始終返回一個數組。

 

查找起點位置的索引。indexOf()從開頭向後查找,lastIndexOf()從末尾向前查找。

 

ECMAScript爲數組定義了5種迭代方法:

  • every() 對數組中的每一項運行給定函數,如果函數對每一項都返回true,則返回true。

  • some() 對數組中的每一項運行給定函數,如果函數對任意一項返回true,則返回true。

  • filter() 對數組中的每一項運行給定函數,返回該函數會返回true的項組成的數組。

  • forEach() 對數組中的每一項運行給定函數,這個函數沒有返回值。

  • map() 對數組中的每一項運行給定函數,返回每次函數調用結果組成的數組

var numbers = [1,2,3,4,5,4,3,2,1];
//item是每一項 index是下標
var filterResult = numbers.filter(function(item, index, array){
    return (item > 2);
 });
alert(filterResult);//[3,4,5,4,3]
var numbers = [1,2,3,4,5,4,3,2,1];
var mapResult = numbers.map(function(item, index, array){ 
    return item * 2;
});
alert(mapResult); //[2,4,6,8,10,8,6,4,2]

reduce()和reduceRight()會迭代數組的所有項,然後構建一個最終返回的值。

/**
 * 演示一個累加
 */
var values = [1,2,3,4,5];
//參數分別是 前一個值、當前值、項的索引、數組對象
var sum = values.reduce(function(prev, cur, index, array){
    return prev + cur;
});
alert(sum); //15

5.3 Date類型

Data.parse()方法接收一個表示日期的字符串參數,然後嘗試根據這個字符串返回相應日期的毫秒數。

Date.UTC()的參數分別是年份、基於0的月份(一月是 0,二月是 1,以此類推)、月中的哪一天 (1 到 31)、小時數(0 到 23)、分鐘、秒以及毫秒數。

Date.now()返回表示調用這個方法時的日期和時間的毫秒數。

Date類型的valueOf()方法返回日期的毫秒錶示,可以方便地使用比較操作符來比較日期值。

ECMAScript 推薦現在編寫的代碼一律使用 toUTCString()方法,它以特定於實現的格式完整的UTC日期。

5.4 RegExp類型

ECMAScript 通過 RegExp 類型來支持正則表達式。使用下面類似 Perl 的語法,就可以創建一個正則表達式。

var expression = / pattern / flags ;

其中模式(pattern)可以是正則表達式,標誌(flags)支持3個標誌:

  • g:表示全局(global),即模式將被應用於所有字符串,而非在發現第一個匹配項時立即停止;
  • i:表示不區分大小寫(case-insensitive)模式,即在確定匹配項時忽略模式與字符串的大小寫;
  • m:表示多行(multiline)模式,即在到達一行文本末尾時還會繼續查找下一行中是否存在與模式匹配的項。

與其他語言中的正則表達式類似,模式中使用的所有元字符都必須轉義。正則表達式中的元字符包括:

( [ { \ ^ $ | ) ? * + .]}

在前面價格\進行轉義,如?變成\? 

 

每個RegExp實例都有如下屬性:

  • global:布爾值,表示是否設置了 g 標誌。
  • ignoreCase:布爾值,表示是否設置了 i 標誌。
  • lastIndex:整數,表示開始搜索下一個匹配項的字符位置,從 0 算起。
  • multiline:布爾值,表示是否設置了 m 標誌。
  • source:正則表達式的字符串表示,按照字面量形式而非傳入構造函數中的字符串模式返回。

 

RegExp實例有如下方法:

exec()是主要專門爲捕獲組而設計的。

var text = "mom and dad and baby";
var pattern = /mom( and dad( and baby)?)?/gi;
var matches = pattern.exec(text);

alert(matches.index); //0

alert(matches.input); // "mom and dad and baby"
alert(matches[0]);  // "mom and dad and baby"
alert(matches[1]); // " and dad and baby"
alert(matches[2]);// " and baby"

exec()在不設置全局標誌(g)的情況下,始終返回第一個匹配的信息。在設置全局標誌的情況下,會繼續查找新匹配項。

個人體會:小括號是爲了匹配組,即在整體應用pattern後,在應用括號內的pattern。

test(),只接受一個字符串參數,匹配模式返回true,否則返回false,經常被用於if語句中。eg:郵箱驗證等。

RegExp構造函數的屬性,相當於java中的靜態屬性,包括:

除了上面幾個屬性之外,還有多達9個用於存儲捕獲組的構造函數屬性。訪問這些屬性的語法是RegExp.$1RegExp.$2...RegExp.$9,分別用於存儲第一、第二......第九個匹配的捕獲組。在 調用 exec()或 test()方法時,這些屬性會被自動填充。

5.5 Function類型

在ECMAScript中,每個函數都是Function的實例,函數名實際上是一個指向函數對象的指針。

使用不帶圓括號的函數名是訪問函數指針,而非調用函數。

ECMAScript中沒有重載的概念。

解析器在向執行環 境中加載數據時,對函數聲明和函數表達式並非一視同仁。解析器會率先讀取函數聲明,並使其在執行任何代碼之前可用(可以訪問);至於函數表達式,則必須等到解析器執行到它所在的代碼行,纔會真正被解釋執行。

從一個函數中返回另一個函數,這是極爲有用的計數。之前我們針對sort()寫過比較函數,如果傳入的是對象,比較函數能傳入根據哪個參數進行排序,那就更好了。例如:可以按照姓名排序,也可按照年齡排序。

var data = [{name: "Zachary", age: 28}, {name: "Nicholas", age: 29}];
data.sort(createComparisonFunction("name")); 
alert(data[0].name); //Nicholas
data.sort(createComparisonFunction("age")); 
alert(data[0].name); //Zachary

在函數內部又兩個特殊對象arguments和this。arguments主要用於保存函數參數,arguments還有一個名叫callee的屬性,是一個指針,指向arguments對象的函數。應用場景:

//遞歸調用
function factorial(num){ 
     if (num <=1) {
            return 1;
     } else {
            return num * factorial(num-1)
     }
}

//升級版遞歸調用
function factorial(num){ 
     if (num <=1) {
            return 1;
     } else {
            return num * arguments.callee(num-1)
     }
}

第一代遞歸調用中的factorial這個函數名被“寫死”進了函數體中,耦合性太高,而升級版的遞歸調用和老版本實現的功能一樣,但不會受“factorial”這一串字符串的限制。不論引用的函數是什麼名字,都可以保證正常完成遞歸調用。

this應用的是函數執行的環境對象。

還有個函數對象屬性caller保存着調用當前函數的函數的引用,如果在全局作用域調用當前函數,它爲null。

 

每個函數都含有兩個屬性:length屬性表示函數接收都命名參數的個數。prototype保存着toString()和valueOf()等方法,不過是通過各自對象的實例來訪問罷了。

每個函數都包含兩個非繼承而來的方法:apply()和call()。這兩個方法的用途都是在特定的作用域中調用函數,實際上等於設置函數體內this對象的值。第一個參數都是運行函數作用域,他倆的區別是第二個參數傳參的形式不同,apply傳入的是參數數組,call傳入的是參數們。

但傳遞參數並非apply()和call()真正的用武之地:它們的真正強大的地方在於能夠擴充函數賴以運行的作用域:

window.color = "red";
var o = { color: "blue" };
function sayColor(){ 
    alert(this.color);
}
sayColor();//red
sayColor.call(this); //red
sayColor.call(window); //red
sayColor.call(o);//blue

使用 call()(或 apply())來擴充作用域的最大好處,就是對象不需要與方法有任何耦合關係。

ECMAScript還定義了bind()這個方法會創建一個函數的實例,其this值會被綁定傳給bind()函數的值。

window.color = "red";
var o = { color: "blue" };
function sayColor(){ 
    alert(this.color);
}
var objectSayColor = sayColor.bind(o); 
objectSayColor(); //blue

在這裏,sayColor()調用 bind()並傳入對象 o,創建了 objectSayColor()函數。object- SayColor()函數的 this 值等於 o,因此即使是在全局作用域中調用這個函數,也會看到"blue"。

5.6 基本包裝類型

基本類型不是對象,從邏輯上講,它不應該有方法(但它們的確有方法)。其實訪問過程處於一種讀取模式,後臺都會自動完成下列問題:

  1. 創建String類型的一個實例
  2. 在實例上調用制定的方法
  3. 銷燬這個實例

引用類型和基本包裝類型的主要區別就是對象的生存期。使用new操作符創建的引用類型的實例,在執行流離開當前作用域之前都一直保存在內存中。而自動創建的基本包裝類型的對象,則只存在與代碼的執行瞬間,然後立即被銷燬。這意味着我們不能在運行時爲基本類型值添加屬性和方法。

對基本包裝類型的實例調用“typeof”會返回“object”,而且所有基本包裝類型的對象在轉化爲布爾類型值時都是true。

 

使用 new 調用基本包裝類型的構造函數,與直接調用同名的轉型函數是不一樣的。 例如:

var value = "25";
var number = Number(value); //轉型函數 
alert(typeof number); //"number"
var obj = new Number(value); //構造函數 
alert(typeof obj); //"object"

變量number中保存的是基本類型值25,而變量obj中保存的是Number的實例。

 

我們建議永遠不用使用Boolean對象。

 

Number類型的toString()方法中,傳入的參數代表進制轉化:

var num = 10; 
alert(num.toString()); //"10" 
alert(num.toString(2)); //"1010" 
alert(num.toString(8)); //"12" 
alert(num.toString(10)); //"10" 
alert(num.toString(16)); //"a"

toFixed()方法會按照制定的小數位返回數值的字符串表示。(保留多少位小數)

toExponential()返回以指數表示法(也稱e表示法)表示的數值的字符串形式:

var num = 10;
alert(num.toExponential(1)); //"1.0e+1"

不過像這種數值太小的數字,一般不使用toExponential()方法,爲了更加“智能”地選擇我們該用什麼方法表示,我們可以使用toPrecision()方法。它會自動決定是調用toFixed()或toExponential()

 

對於String類型,charAt()方法以單字符字符串的形式返回給定位置的那個字符(ECMAScript中沒有字符類型)。

如果你想返回的不是字符而是字符編碼,需要使用charCodeAt()。

ECMAScript還定義了另一個訪問個別字符的方法,可以使用方括號加數字索引來訪問某個字符:

var stringValue = "hello world";
alert(stringValue[1]);   //"e"

 

ECMAScript還提供了三個基於字符串創建新字符串的方法:slice()、substr()、sunstring()。都是爲了切割字串而存在。

indexOf()和lastIndexOf()是從字符串中查找自字符串的方法。

trim()方法會刪除前置和後綴的所有空格,然後返回結果。

 

與大小寫轉換有關的方法:toLowerCase()、toLocaleLowerCase()、toUpperCase()和 toLocaleUpperCase()。其中帶Locale的方法可以根據地區的運行環境保證正確的轉換,所以更穩妥一些。

 

字符串模式匹配,使用match()方法,本質是與調用RegExp()和exec()的方法相同。只接受一個參數,要麼是一個正則表達式,要麼是一個RegExp對象。返回一個數組,數組的第一項是與整個模式匹配的字符串,之後的每 一項(如果有)保存着與正則表達式中的捕獲組匹配的字符串。

另一個用於查找模式的方法是search(),與match()方法參數相同,返回第一個匹配項的索引。

爲了簡化替換子字符串的操作,ECMAScript提供了replace()方法。

最後一個與模式匹配有關的方法是 split(),這個方法可以基於指定的分隔符將一個字符串分割成 多個子字符串,並將結果放在一個數組中。

與操作字符串有關的最後一個方法是 localeCompare(),這個方法比較兩個字符串。

另外,String 構造函數本身還有一個靜態方法:fromCharCode()。這個方法的任務是接收一或 多個字符編碼,然後將它們轉換成一個字符串。從本質上來看,這個方法與實例方法 charCodeAt() 執行的是相反的操作。

5.7 單體內置對象

ECMA-262還定義了兩個單體對象Global和Math。

ECMAScript 中的 Global 對象在某種意義上是作爲一個終極的“兜底兒對象” 來定義的。換句話說,不屬於任何其他對象的屬性和方法,最終都是它的屬性和方法。事實上,沒有全 局變量或全局函數;所有在全局作用域中定義的屬性和函數,都是 Global 對象的屬性。前面介紹 過的那些函數,諸如 isNaN()、isFinite()、parseInt()以及 parseFloat(),實際上全都是 Global 對象的方法。除此之外,Global 對象還包含其他一些方法。

Global 對象的 encodeURI()和 encodeURIComponent()方法可以對 URI進行編碼,以便發送給瀏覽器。

encodeURI()主要用於整個 URI(例如,http://www.wrox.com/illegal value.htm),而 encode- URIComponent()主要用於對 URI 中的某一段(例如前面 URI 中的 illegal value.htm)進行編碼。

與 encodeURI()和 encodeURIComponent()方法對應的兩個方法分別是 decodeURI()和 decodeURIComponent()。

 

eval() 方法就像是一個完整的ECMAScript解析器,它只接受一個參數,即要執行的ECMAScrip(t或JavaScript) 字符串。

當解析器發現代碼中調用 eval()方法時,它會將傳入的參數當作實際的 ECMAScript 語句來解析, 然後把執行結果插入到原位置。通過 eval()執行的代碼被認爲是包含該次調用的執行環境的一部分, 因此被執行的代碼具有與該執行環境相同的作用域鏈。

特殊的值undefined、NaN 以及 Infinity 都是 Global 對象的屬性。此外,所有原生引用類型的構造函數,像 Object 和 Function,也都是 Global 對象的屬性。下表列出了 Global 對象的所有屬性:

 

ECMAScript 雖然沒有指出如何直接訪問 Global 對象,但 Web 瀏覽器都是將這個全局對象作爲 window 對象的一部分加以實現的。

另一種取得 Global 對象的方法是使用以下代碼:

var global = function(){ 
    return this;
}();

 以上代碼創建了一個立即調用的函數表達式,返回 this 的值。如前所述,在沒有給函數明確指定 this 值的情況下(無論是通過將函數添加爲對象的方法,還是通過調用 call()或 apply()),this 值等於 Global 對象。而像這樣通過簡單地返回 this 來取得 Global 對象,在任何執行環境下都是可 行的。

 

在Math對象中,

min()和 max()方法用於確定一組數值中的最小值和最大值。

Math.ceil()執行向上舍入。

Math.floor()執行向下舍入。

Math.round()執行標準舍入。(四捨五入)

Math.random()方法返回大於等於 0 小於 1 的一個隨機數。

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