5 引用類型

本章內(nèi)容

  • 使用對象
  • 創(chuàng)建并操作數(shù)組
  • 理解基本的 JavaScript 類型
  • 使用基本類型和基本包裝類型

引用類型的值(對象)是引用類型的一個實例。

雖然引用類型與類看起來相似,但它們并不是相同的概念。為避免混淆,本書將不使用類這個概念。

新對象是使用new操作符跟一個構(gòu)造函數(shù)來創(chuàng)建的。

var person = new Object();

這行代碼創(chuàng)建了Object引用類型的一個新實例,然后把該實例保存在了變量person中。使用的構(gòu)造函數(shù)是Object,它只為新對象定義了默認(rèn)的屬性和方法。

5.1 Object 類型

創(chuàng)建Object實例的方式有兩種。第一種是使用new操作符后跟Object構(gòu)造函數(shù)。

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

另一種是使用對象字面量表示法。

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

在使用對象字面量語法時,屬性名也可以使用字符串。

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

這個例子會創(chuàng)建一個對象,包含三個屬性:nameage5。但這里的數(shù)值屬性會自動轉(zhuǎn)換為字符串。
另外,使用對象字面語法時,如果留空其花括號,則可以定義只包含默認(rèn)屬性和方法的對象。

var person = {};  //與new Object()相同
person.name = "Nicholas";
person.age = 29;

開發(fā)人員更青睞對象字面量語法。實際上,對象字面量也是向函數(shù)傳遞大量可選參數(shù)的首選方式。

function displayInfo(args) {
  var output = "";
  if (typeof args.name == "string") {
    output += "Name: " + args.name + "\n";
  }
  if (typeof args.age == "number") {
    output += "Age: " + args.age + "\n";
  }
  alert(output);
}

displayInfo({
  name: "Nicholas",
  age: 29
});

displayInfo({
  name: "Greg"
});

這種傳遞參數(shù)的模式最適合需要向函數(shù)傳入大量可選參數(shù)的情形。

一般來說,訪問對象屬性時使用的都是點表示法,這也是很多面向?qū)ο笳Z言中通用的語法。在JavaScript也可以使用方括號表示來訪問對象的屬性。使用方括號語法時,應(yīng)該將要訪問的屬性以字符串形式放在方括號中。

alert(person["name"]);  //"Nicholas"
alert(person.name);  //"Nicholas"

從功能上看,這兩種訪問對象屬性的方法沒有任何區(qū)別。但方括號語法的主要優(yōu)點是可以通過變量來訪問屬性。

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

通常,除非必須使用變量來訪問屬性,否則我們建議使用點表示法。

5.2 Array 類型

ECMAScript 中的數(shù)組與其他多數(shù)語言中的數(shù)組有著相當(dāng)大的區(qū)別。雖然 ECMAScript 數(shù)組與其他語言中的數(shù)組都是數(shù)據(jù)的有序列表,但與其他語言不同的是,ECMAScript 數(shù)組的每一項可以保存任何類型的數(shù)據(jù)。而且,ECMAScript 數(shù)組的大小是可以動態(tài)調(diào)整的,即可以隨著數(shù)據(jù)的添加自動增長以容納新增數(shù)據(jù)。
創(chuàng)建數(shù)組的基本方式有兩種。第一種是使用Array構(gòu)造函數(shù)。

var colors = new Array();

如果預(yù)先知道數(shù)組要保存的項目數(shù)量,也可以給構(gòu)造函數(shù)傳遞該數(shù)量,而該數(shù)量會自動變成length屬性的值。

var colors = new Array(20);

也可以向Array構(gòu)造函數(shù)傳遞數(shù)組中應(yīng)該包含的項。

var colors = new Array("red", "blue", "green");

傳遞一個值也可以創(chuàng)建數(shù)組。

var colors = new Array(3);  //創(chuàng)建一個包含3項的數(shù)組
var names = new Array("Greg");  //創(chuàng)建一個包含1項,即字符串“Greg”的數(shù)組

創(chuàng)建數(shù)組的第二種基本方式是使用數(shù)組字面量表示法。

var colors = ["red", "blue", "green"];
var names = [];

與對象一樣,在使用數(shù)組字面量表示法時,也不會調(diào)用Array構(gòu)造函數(shù)。

var colors = ["red", "blue", "green"];
alert(colors[0]);
colors[2] = "black";  //修改第三項
colors[3] = "brown";  //新增第四項

數(shù)組的項數(shù)保存在其length屬性中,這個屬性始終返回0或更大的值。

var colors = ["red", "blue", "green"];  
var names = [];
alert(colors.length);  //3
alert(names.length);  //0

數(shù)組的length屬性不是只讀的。通過設(shè)置這個屬性,可以從數(shù)組的末尾移除或向數(shù)組中添加新項。

var colors = ["red", "blue", "green"];
colors.length = 2;
alert(colors[2]);  //undefined

利用length屬性也可以方便地在數(shù)組末尾添加新項。

var colors = ["red", "blue", "green"];
colors[colors.length] = "black";
colors[colors.length] = "brown";

當(dāng)把一個值放在超出當(dāng)前數(shù)組大小的位置上時,數(shù)組就會重新計算其長度值,即長度值等于最后一項的索引加 1。

var colors = ["red", "blue", "green"];
colors[99] = "black";
alert(colors.length);  //100

數(shù)組位置 3 到位置 98 實際上都是不存在的,所以訪問它們都將返回undefined

數(shù)組最多可以包含 4294967295 個項,這幾乎已經(jīng)能夠滿足任何編程需求了。

5.2.1 檢測數(shù)組

ECMAScript 5 新增了Array.isArray()方法。這個方法的目的是最終確定某個值到底是不是數(shù)組,而不管它是在哪個全局執(zhí)行環(huán)境中創(chuàng)建的。

if (Array.isArray(value)) {
  //對數(shù)組執(zhí)行某些操作
}

5.2.2 轉(zhuǎn)換方法

所有方法都具有toLocalString()toString()valueOf()方法。其中,調(diào)用數(shù)組的toString()方法會返回由數(shù)組中每個值得字符串形式拼接而成的一個以逗號分隔的字符串。而調(diào)用valueOf()返回的還是數(shù)組。實際上,為了創(chuàng)建這個字符串會調(diào)用數(shù)組每一項的toString()方法。

var colors = ["red", "blur", "green"];
alert(colors.toString());  //red,blue,green
alert(colors.valueOf());  //red,blue,green
alert(colors);  //red,blue,green

最后一行代碼直接將數(shù)組傳遞給了alert()。由于alert()要接收字符串參數(shù),所以它會在后臺調(diào)用toString()方法,由此會得到與直接調(diào)用toString()方法相同的結(jié)果。

另外,toLocaleString()方法經(jīng)常也會返回前兩個方法相同的值。與前兩個方法唯一不同之處在于,這一次為了取得每一項的值,調(diào)用的是每一項的toLocaleString()方法,而不是toString()方法。

var person1 = {
  toLocaleString : function() {
    return "Nikolaos";
  }
  toString : function() {
    return "Nicholas";
  }
};

var person2 = {
  toLocaleString : function() {
    return "Grigorios";
  }
  toString : function() {
    return "Greg";
  }
};

var people = [person1, person2];
alert(people);  //Nicholas,Greg
alert(people.toString());  //Nicholas,Greg
alert(people.toLocaleString());  //Nikolaos,Grigorios

如果使用join()方法,則可以使用不同的分隔符來構(gòu)建這個字符串。join()方法只接收一個參數(shù),即用作分隔符的字符串,然后返回包含所有數(shù)組項的字符串。如果不給join()方法傳入任何值,或者給它傳入undefined,則使用逗號作為分隔符。

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

如果數(shù)組中的某一項的值是null或者undefined,那么該值在join()toLocaleString()toString()valueOf()方法返回的結(jié)果以空白字符串表示。

5.2.3 棧方法

ECMAScript 為數(shù)組專門提供了push()pop()方法,以便實現(xiàn)類似棧的行為。
push()方法可以接收任意數(shù)量的參數(shù),把它們逐個添加到數(shù)組末尾,并返回修改后數(shù)組的長度。而pop()方法則從數(shù)組末尾移除最后一項,減少數(shù)組的length值,然后返回移除的項。

var colors = new Array();
var count = colors.push("red", "green");
alert(count);  //2
count = colors.push("black");
alert(count);
var item = colors.pop();
alert(item);  //"black"
alert(colors.length);  //2

5.2.4 隊列方法

棧數(shù)據(jù)結(jié)構(gòu)的訪問規(guī)則是LIFO(后進先出),而隊列數(shù)據(jù)結(jié)構(gòu)的訪問規(guī)則是FIFO(先進先出)。shift()能夠移除數(shù)組中的第一個項并返回該項,同時將數(shù)組長度減1。結(jié)合使用shift()push()方法,可以像使用隊列一樣使用數(shù)組。

var colors = new Array();
var count = colors.push("red", "green");
alert(count);  //2
count = colors.push("black");
alert(count);  //3
var item = colors.shift();
alert(item);  //"red"
alert(colors.length);  //2

ECMAScript還為數(shù)組提供了一個unshift()方法。它能在數(shù)組前端添加任意個項并返回新數(shù)組的長度。因此,同時使用unshift()pop()方法,可以從相反的方向來模擬隊列,即在數(shù)組的前端添加項,從數(shù)組末端移除項。

var colors = new Array();
var count = colors.unshift("red", "green");
alert(count);  //2
count = colors.unshift("black");
alert(count);  //3
var item = colors.pop();
alert(item);  //"green"
alert(colors.length);  //2

IE7及更早版本中其unshift()方法總是返回undefined值。

5.2.5 重排序方法

數(shù)組中已經(jīng)存在兩個可以直接用來重排序的方法:reverse()sort()

var values = [1, 2, 3, 4, 5];
values.reverse();
alert(values);  //5,4,3,2,1

在默認(rèn)情況下,sort()方法按升序排列數(shù)組項。sort()方法會調(diào)用每個數(shù)組項的toString()轉(zhuǎn)型方法,然后比較得到的字符串,以確定如何排序。

var values = [0, 1, 5, 10, 15];
values.sort();
alert(values);  //0,1,10,15,5

可見,即使例子中值得順序沒有問題,但sort()方法會根據(jù)測試字符串的結(jié)果改變原來的順序。字符串比較時,“10”位于“5”的前面。sort()方法可以接收一個比較函數(shù)作為參數(shù),以便我們指定那個值位于那個值的前面。
以下就是一個簡單的比較函數(shù):

function compare(value, value) {
  if (value1 < value2) {
    return -1;
  } else if (value1 > value2) {
    return 1;
  } else {
    return 0;
  }
}
var values = [0, 1, 5, 10, 15];
values.sort(compare);
alert(values);  //0,1,5,10,15

也可以通過比較函數(shù)產(chǎn)生降序排序的結(jié)果,只要交換比較函數(shù)返回的值即可。

function compare (value1, value2) {
  if (value1 < value2) {
    return 1;
  } else if (value1 > value2) {
    return -1;
  } else { 
    return 0;
  }
}

var values = [0, 1, 5, 10, 15];
values.sort(compare);
alert(values);  //15,10,5,1,0

對于數(shù)值類型或者其valueOf()方法會返回數(shù)值類型的對象類型,可以使用一個更簡單的比較函數(shù)。這個函數(shù)只要用第二個值減第一個值即可。

function compare(value1, value2) {
  return value2 - value1;
}

5.2.6 操作方法

concat()方法可以基于當(dāng)前數(shù)組中的所有項創(chuàng)建一個新數(shù)組。具體來說,這個方法會先創(chuàng)建當(dāng)前數(shù)組一個副本,然后將接收到的參數(shù)添加到這個副本的末尾,最后返回新構(gòu)建的數(shù)組。在沒有給concat()方法傳遞參數(shù)的情況下,它只是復(fù)制當(dāng)前數(shù)組并返回副本。如果傳遞給concat()方法的是一或多個數(shù)組,則該方法會將這些數(shù)組中的每一項都添加到結(jié)果數(shù)組中。如果傳遞的值不是數(shù)組,這些值就會被簡單地添加到結(jié)果數(shù)組的末尾。下面來看一個例子。

var colors = ["red", "green", "blue"];
var colors2 = colors.concat("yellow", ["black", "brown"]]);
alert(colors);  //red,green,blue
alert(colors2);  //red,green,blue,yellow,black,brown

slice()能夠基于當(dāng)前數(shù)組中的一或多個項創(chuàng)建一個新數(shù)組。slice()方法可以接受一或兩個參數(shù),即要返回項的起始和結(jié)束位置。若只有一個參數(shù),slice()方法返回從該參數(shù)指定位置開始到當(dāng)前數(shù)組末尾的所有項。如果有兩個參數(shù),該方法返回起始和結(jié)束位置之間的項——但不包括結(jié)束位置的項。注意,slice()方法不會影響原始數(shù)組。

var colors = ["red", "green", "blue", "yellow", "purple"];
var colors2 = colors.slice(1);
var colors3 = colors.slice(1,4);

alert(colors2);  //green,blue,yellow,purple
alert(colors3);  //green,blue,yellow

如果slice()方法的參數(shù)中有一個負(fù)數(shù),則用數(shù)組長度加上該數(shù)來確定相應(yīng)的位置。例如,在一個包含5項的數(shù)組上調(diào)用slice(-2,-1)與調(diào)用slice(3,4)的到的結(jié)果相同。如果結(jié)束位置小于起始位置,則返回空數(shù)組。

splice()方法的主要用途是向數(shù)組的中部插入項,但使用這種方法的方式則有如下3種。

  • 刪除: 可以刪除任意數(shù)量的項,只需指定2個參數(shù):要刪除的第一項的位置和要刪除的項數(shù)。例如,splice(0,2)會刪除數(shù)組中的前兩項。
  • 插入:可以向指定位置插入任意數(shù)量的項,只需提供3個參數(shù):起始位置、0(要刪除的項數(shù))和要插入的項。如果要插入多個項,可以再傳入第四、第五,以至任意多個項。例如,splice(2,0,"red","green")會從當(dāng)前數(shù)組的位置2開始插入字符串“red”和“green”。
  • 替換: 可以向指定位置插入任意數(shù)項的項,且同時刪除任意數(shù)量的項,只需指定3個參數(shù):起始位置、要刪除的項數(shù)和要插入的任意數(shù)量的項。插入的項數(shù)不必與刪除的項數(shù)相等。例如,splice(2,1,"red","green")會刪除當(dāng)前數(shù)組位置2的項,然后自從位置2開始插入字符串“red”和“green”。

splice方法始終都會返回一個數(shù)組,該數(shù)組中包含從原始數(shù)組中刪除的項(如果沒有刪除任何項,則返回一個空數(shù)組)。下面的代碼展示了上述3種使用splice()方法的方式。

var colors = ["red", "green", "blue"];
var removed = colors.splice(0,1);  //刪除第一項
alert(colors);  //green, blue
alert(removed);  //red

removed = colors.splice(1, 0, "yellow", "orange");  //從位置1開始插入兩項
alert(colors);  //green,yellow,yellow,orange,blue
alert(removed);  //返回的是一個空數(shù)組

removed = colors.splice(1, 1, "red",  "purple");  //插入兩項,刪除一項
alert(colors);  //green,red,purple,orange,blue
alert(removed);  //yellow, 返回的數(shù)組中只包含一項

5.2.7 位置方法

ECMAScript5 為數(shù)組實例添加了兩個位置方法: indexOf()lastIndexOf()。這兩個方法都接收兩個參數(shù):要查找的項和(可選的)表示查找起點位置的索引。indexOf()方法從數(shù)組的開頭(位置0)開始向后查找。lastIndexOf()方法則從數(shù)組的末尾開始向前查找。
這倆方法都返回要查找的項在數(shù)組中的位置,或者在沒找到的情況下返回-1.在比較第一個參數(shù)與數(shù)組中的每一項時,會使用全等操作符。

var numbers = [1,2,3,4,5,4,3,2,1];
alert(numbers.indexOf(4));  //3
alert(numbers.lastIndexOf(4));  //5
alert(numbers.indexOf(4,4));  //5

var person = {name: "Nicholas"};
var people = [{name: "Nicholas"}];
var morePeople = [person];
alert(people.indexOf(person));  //-1
alert(morePeople.indexOf(person));  //0

5.2.8 迭代方法

ECMAScript5 為數(shù)組定義了5個迭代方法。每個方法都接收兩個參數(shù):要在每一項上運行的函數(shù)和(可選的)運行該函數(shù)的作用域?qū)ο蟆绊?code>this的值。傳入這些方法中的函數(shù)會接收三個參數(shù):數(shù)組項的值、該項在數(shù)組中的位置和數(shù)組對象本身。

  • every():對數(shù)組中的每一項運行給定函數(shù),如果該函數(shù)對每一項都返回true,則返回true
  • filter():對數(shù)組中的每一項運行給定函數(shù),返回該函數(shù)會返回true的項組成的數(shù)組。
  • forEach():對數(shù)組中的每一項運行給定函數(shù)。這個方法無返回值。
  • map():對數(shù)組中的每一項運行給定函數(shù),返回每次函數(shù)調(diào)用的結(jié)果組成的數(shù)組。
  • some():對數(shù)組中的每一項運行給定函數(shù),如果該函數(shù)對任一項返回true,則返回true
    以上方法都不會修改數(shù)組中的包含的值。
var numbers = [1,2,3,4,5,4,3,2,1];
var everyResult = numbers.every(function(item, index, array) {
  return (item > 2);
});
alert(everyResult);  //false
var someResult = numbers.some(function(item, index, array) {
  return (item > 2);
});
alert(someResult);  //true
var numbers = [1,2,3,4,5,4,3,2,1];
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]

forEach()這個方法沒有返回值,只是對數(shù)組中的每一項運行傳入的函數(shù)本質(zhì)上與使用for循環(huán)迭代數(shù)組一樣。

var numbers = [1,2,3,4,5,4,3,2,1];
numbers.forEach(function(item, index, array) {
  //執(zhí)行某些操作
});

5.2.9 縮小方法

ECMAScript 5 新增了倆縮小數(shù)組的方法:reduce()reduceRight。這倆方法都會迭代數(shù)組的所有想,然后構(gòu)建一個最終返回的值。其中,reduce()方法從數(shù)組的第一項開始,逐個遍歷到最后。而reduceRight()則從數(shù)組的最后一項開始,向前遍歷到第一項。
這倆方法都接收兩個參數(shù):一個在每一項調(diào)用的函數(shù)和(可選)作為縮小基礎(chǔ)的初始值。傳給reduce()reduceRight()的函數(shù)接收 4 個參數(shù):前一個值、當(dāng)前項、項的索引和數(shù)組對象。這個函數(shù)返回的任何值都會作為第一個參數(shù)自動傳給下一項。第一次迭代發(fā)生在數(shù)組的第二項,因此第一個參數(shù)是數(shù)組的第一項,第二個參數(shù)就是數(shù)組的第二項。
使用reduce()方法可以執(zhí)行求數(shù)組中所有值之和的操作。

var values = [1,2,3,4,5]; 
var sum = values.reduce(function(prev, cur, index, array) {
  return prev + cur;
});
alert(sum);  //15
var values = [1,2,3,4,5];
var sum = values.reduceRight(function(prev, cur, index, array) {
  return prev + cur;
});
alert(sum);  //15

5.3 Date 類型

Date類型使用自 UTC 1970 年 1 月 1 日 零時開始經(jīng)過的毫秒數(shù)來保存日期。
使用new操作符和Date構(gòu)造函數(shù)即可。

var now = new Date();

如果想根據(jù)特定的日期和時間創(chuàng)建日期對象,必須傳入表示該日期的毫秒數(shù)。為了簡化計算過程,提供了倆方法:Date.parse()Date.UTC()
Date.parse()方法接收一個表示日期的字符串參數(shù),然后嘗試根據(jù)這個字符串返回相應(yīng)日期的毫秒數(shù)。
如果傳入的字符串不能表示日期,那么它會返回NaN。實際上,如果直接將表示日期的字符串傳遞給Date構(gòu)造函數(shù),也會在后臺調(diào)用Date.parse()

var someDate = new Date("May 25, 2004");

Date.UTC()方法同樣返回表示日期的毫秒數(shù),但它與Date.parse()在構(gòu)建時使用不同的信息。參數(shù)分別是年份、基于0的月份,月中的哪一天、小時數(shù)(0到23)、分鐘、秒以及毫秒數(shù)。這些參數(shù)中,只有前兩個參數(shù)是必須的。如果沒有提供月中天數(shù),擇假設(shè)天數(shù)為1;如果省略其他參數(shù),則統(tǒng)統(tǒng)假設(shè)為0。

var y2k = new Date(Date.UTC(2000, 0));

var allFives = new Date(Date.UTC(2005, 4, 5, 17, 55, 55));

Date構(gòu)造函數(shù)也會模仿Date.UTC(),但有一點明顯不同:日期和時間都基于本地時區(qū)而非GMT來創(chuàng)建。
ECMAScript 5 添加了Date.now()方法,返回表示調(diào)用這個方法時的日期和時間的毫秒數(shù)。這個方法簡化了使用Date對象分析代碼的工作。

var start = Date.now();

doSomething();

var stop = Date.now(),
result = stop - start;

5.3.1 繼承的方法

與其他引用類型一樣,Date類型也重寫了toLocaleString()toString()valueOf()方法;但這些方法返回的值與其他類型中的方法不同。Date類型的 toLocaleString()方法會按照與瀏覽器設(shè)置的地區(qū)相適應(yīng)的格式返回日期和時間。而toString()方法則通常會返回帶有時區(qū)信息的日期和時間,其中時間一般以軍用時間(0到23)表示。
至于Date類型的valueOf()方法,則根本不返回字符串,而是返回日期的毫秒表示。因此,可以方便使用比較操作符來比較日期值。

var date1 = new Date(2007, 0, 1);
var date2 = new Date(2007, 1, 1);

alert(date1 < date2); //true
alert(date1 > date2);  //false

5.3.2 日期格式化方法

Date類型還有一些專門用于將日期格式化為字符串的方法。

  • toDateString()——以特定于實現(xiàn)的格式顯示星期幾、月、日和年;
  • toTimeString()——以特定于實現(xiàn)的格式顯示時、分、秒和時區(qū);
  • toLocaleDateString()——以特定于地區(qū)的格式顯示星期幾、月、日和年;
  • toLocaleTimeString()——以特定于實現(xiàn)的格式顯示時、分、秒;
  • toUTCString()——以特定于實現(xiàn)的格式完整的UTC日期。

以上這些字符串格式方法的輸出也是因瀏覽器而異的,因此沒有哪一個方法能夠用來在用戶界面中顯示一致的日期信息。

5.3.3 日期/時間組件方法

方法 說明
getTime() 返回表示日期的毫秒數(shù);與valueOf()方法返回的值相同
setTime(毫秒) 以毫秒數(shù)設(shè)置日期,會改變整個日期
getFullYear() 取的4位數(shù)的年份
getUTCFullYear() 返回UTC日期的4位數(shù)年份
getMonth() 返回日期的月份,其中0表示一月
getUTCMonth() 。。。
setMonth(月) 設(shè)置日期的月份,必須大于0,超過11增加年份
setUTCMonth(月)
getDate() 返回日期月份中的天數(shù)
getUTCDate()
setDate(日) 設(shè)置日期月份中的天數(shù)。如果傳入的值超過了該月中應(yīng)有的天數(shù),則增加月份
setUTCDate()
getDay() 返回日期中星期的星期幾(其中0表示星期日,6表示星期六)
getUTCDay()
getHours() 返回日期中的小時數(shù)(0到23)
getUTCHours()
setHours(時) 設(shè)置日期中的小時數(shù)。傳入的值超過了23則增加月份中的天數(shù)
setUTCHours(時)
getMinutes() 返回日期中的分鐘數(shù)
getUTCMinutes()
setMinutes(分) 設(shè)置日期中的分鐘數(shù)。傳入的值超過59則增加小時數(shù)
setUTCMinutes(分)
getSeconds() 返回日期中的秒數(shù)
getUTCSeconds()
setSeconds(秒) 設(shè)置日期中的秒數(shù)。傳入的值超過了59會增加分鐘數(shù)
setUTCSeconds(秒)
getMilliseconds() 返回日期中的毫秒數(shù)
getUTCMilliseconds()
setMilliseconds(毫秒) 設(shè)置日期中的毫秒數(shù)
setUTCMilliseconds(毫秒)
getTimezoneOffset() 返回本地時間與UTC時間相差的分鐘數(shù)。

5.4 RegExp 類型

ECMAScript通過RegExp類型來支持正則表達(dá)式。

var expression = / pattern / flags ;

其中的模式(pattern)部分可以是任何簡單或復(fù)雜的正則表達(dá)式,可以包含字符類、限定類、分組、向前查找以及反向引用。每個正則表達(dá)式都可帶有一或多個標(biāo)志(flags),用以標(biāo)明正則表達(dá)式的行為。正則表達(dá)式的匹配模式支持下列3個標(biāo)志。

  • g: 表示全局模式,即模式將被應(yīng)用于所有字符串,而非在發(fā)現(xiàn)第一個匹配項時立即停止;
  • i:表示不區(qū)分大小寫模式,即再確定匹配時忽略模式與字符串的大小寫;
  • m:表示多行模式,即在到達(dá)一行文本末尾時還會繼續(xù)查找下一行中是否存在與模式匹配的項。

因此,一個正則表達(dá)式就是一個模式與上述3個標(biāo)志的組合體。不同組合產(chǎn)生不同結(jié)果。

//匹配字符串中所有“at”的實例
var pattern1 = /at/g;
//匹配第一個“bat”或“cat”,不區(qū)分大小寫
var pattern2 = /[bc]at/i;
//匹配所有以“at”結(jié)尾的3個字符的組合,不區(qū)分大小寫
var pattern3 = /.at/gi;

與其他元字符在正則表達(dá)式中都有一或多種特殊用途,因此如果想要匹配字符串中包含的這些字符,就必須對它們進行轉(zhuǎn)義。

另一種創(chuàng)建正則表達(dá)式的方式是使用RegExp構(gòu)造函數(shù),它接收兩個參數(shù):一個是要匹配的字符串模式,另一個是可選的標(biāo)志字符串。

var pattern1 = /[bc]at/i;

var pattern2 = new RegExp("[bc]at", "i");

要注意的是,傳遞給RegExp構(gòu)造函數(shù)的兩個參數(shù)都是字符串。在某些情況下要對字符進行雙重轉(zhuǎn)義。所有元字符都必須雙重轉(zhuǎn)義,那些已經(jīng)轉(zhuǎn)義的字符也是如此,例如\n(字符\在字符串中通常被轉(zhuǎn)義為\,而在正則表達(dá)式字符串中就會變成\\)。下表給出了一些模式。

字面量模式 等價的字符串
/[bc]at/ "\[bc\]at"
/.at/ "\.at"
/name/age/ "name\/age"
/\d.\d{1,2}/ "\d.\d{1,2}"
/\w\hello\123/ "\w\\hello\\123"

使用正則表達(dá)式字面量和使用RegExp構(gòu)造函數(shù)創(chuàng)建的表達(dá)式不一樣。
ECMAScript 5 明確規(guī)定,使用正則表達(dá)式字面量必須像直接調(diào)用RegExp構(gòu)造函數(shù)一樣,每次都創(chuàng)建新的RegExp實例。IE9+、Firefox 4+ 和 Chrome 都據(jù)此做出了修改。

5.4.1 RegExp 實例屬性

RegExp的每個實例都具有下列屬性,通過這些屬性可以取得有關(guān)模式的各種信息。

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

5.4.2 RegExp 實例方法

RegExp對象的主要方法是exec()exec()接受一個參數(shù),即要應(yīng)用模式的字符串,然后返回包含第一個匹配項信息點數(shù)組;或者在沒有匹配項的情況下返回null。返回的數(shù)組雖然是Array的實例,但包含倆額外的屬性:indexinput。其中,index表示匹配在字符串中的位置,而input表示應(yīng)用正則表達(dá)式的字符串。在數(shù)組中,第一項是與整個模式匹配的字符串,其他項是與模式中的捕獲組匹配的字符串(如果模式中沒有捕獲組,則該數(shù)組只包含一項)。

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()方法而言,即使在模式中設(shè)置了全局標(biāo)志(g),他每次也只會返回一個一個匹配項。在設(shè)置全局標(biāo)志的情況下,每次調(diào)用exec()則都會在字符串中繼續(xù)查找新匹配項,如下面的例子所示。

正則表達(dá)式的第二個方法是test(),它接受一個字符串參數(shù)。在模式與該參數(shù)匹配的情況下返回true;否則,返回false
RegExp實例繼承的toLocaleString()toString()方法都會返回正則表達(dá)式的字面量,于創(chuàng)建方式無關(guān)。

5.4.3 RegExp 構(gòu)造函數(shù)屬性

具體屬性略。
還有多達(dá)9個用于存儲捕獲組的構(gòu)造函數(shù)屬性。訪問這些屬性的語法是RegExp.$1、RegExp.$2...RegExp.$9, 分別用于存儲第一,第二......第九個匹配的捕獲組。在調(diào)用exec()test()方法時,這些屬性會被自動填充。

var text = "this has been a short summer";
var pattern = /(..)or(.)/g;

if(pattern.test(text)) {
  alert(RegExp.$1);  //sh
  alert(RegExp.$2);  //t
}

5.4.4 模式的局限性

下面列出了 ECMAScript 正則表達(dá)式不支持的特性。

  • 匹配字符串開始和結(jié)尾的\A 和 \Z (但支持以插入符號^和美元符號$來匹配字符串的開始和結(jié)尾)
  • 向后查找(但完全支持向前查找)
  • 并集和交集類
  • 原子組
  • Unicode 支持
  • 命名的捕獲組(但支持編號的捕獲組)
  • s(單行)和 x(無間隔)匹配模式
  • 條件匹配
  • 正則表達(dá)式注釋

5.5 Function 類型

每個函數(shù)都是Function類型的實例,而且都與其他引用類型一樣具有屬性和方法。由于函數(shù)是對象,因此函數(shù)名實際上也是一個指向函數(shù)對象的指針,不會與某個函數(shù)綁定。函數(shù)通常是使用函數(shù)聲明語法定義的。

function sum (num1, num2) {
  return num1 + num2;
}

這與下面使用函數(shù)表達(dá)式定義函數(shù)的方式幾乎相差無幾

var sum = function(num1, num2) {
  return num1 + num2;
};

最后一種定義函數(shù)的方式是使用Function構(gòu)造函數(shù),不推薦。

由于函數(shù)名僅僅是指向函數(shù)的指針,因此函數(shù)名與包含對象指針的其他變量沒有什么不同。

function sum(num1, num2) {
  return num1 + num2;
}
alert(sum(10, 10));  //20

var anotherSum = sum;
alert(anotherSum(10, 10));  //20

sum = null;
alert(anotherSum(10, 10));  //20

5.5.1 沒有重載(深入理解)

將函數(shù)名想象為指針,也有助于理解為什么 ECMAScript 中沒有函數(shù)重載的概念。

5.5.2 函數(shù)聲明與函數(shù)表達(dá)式

解析器會率先讀取函數(shù)聲明,并使其在執(zhí)行任何代碼之前可用(可以訪問);至于函數(shù)表達(dá)式,則必須等到解析器執(zhí)行到它所在的代碼行,才會真正被解釋執(zhí)行。

alert(sum(10, 10));
function sum(num1, num2) {
  return num1 + num2;
}

以上代碼正常運行。因為在代碼執(zhí)行之前,解析器就已經(jīng)通過一個名為函數(shù)聲明提升的過程,讀取并將函數(shù)聲明添加到執(zhí)行環(huán)境中。

alert(sum(10, 10));
var sum = function(num1, num2){
  return num1 + num2;
}

以上代碼在運行期間會產(chǎn)生錯誤,原因在于函數(shù)位于一個初始化語句中,而不是一個函數(shù)聲明。

作為值的函數(shù)

因為 ECMAScript 中的函數(shù)本身就是變量,所以函數(shù)也可以作為值來使用。不僅可以像傳遞參數(shù)一樣把一個函數(shù)傳遞給另一個函數(shù),而且可以將一個函數(shù)作為另一個函數(shù)的結(jié)果返回。

function callSomeFunction(someFunction, someArgument) {
  return someFunction(someArgument);
}
function add10(num) {
  return num + 10;
}

var result = callSomeFunction(add10, 10);
alert(result);  //20

當(dāng)然,可以從一個函數(shù)中返回另一個函數(shù),而且這也是極為有用的一種技術(shù)。

function createComparisonFunction(propertyName) {
  return function(object1, object2) {
    var value1 = object1[propertyName];
    var value2 = object2[propertyName];
    
    if (value1 < value2) {return -1;} else if (value1 > value2) {return1;} else  {return 0'}
  };
}
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

5.5.4 函數(shù)內(nèi)部屬性

在函數(shù)內(nèi)容中,有兩個特殊的對象:argumentsthis。其中,arguments()是一個類數(shù)組對象,包含著傳入函數(shù)中的所有參數(shù)。雖然arguments的主要用途是保存函數(shù)參數(shù),但這個對象還有一個名叫callee的屬性,該屬性是一個指針,指向擁有這個arguments對象的函數(shù)。

function factorial (num) {
  if (num <=1) {
    return 1;
  } else {
    return num * factorial(num-1)
  }
}

定義階乘函數(shù)一般都要用到遞歸算法;問題是這個函數(shù)的執(zhí)行與函數(shù)名factorial緊緊耦合在了一起。為了消除這種耦合現(xiàn)象,可以這樣使用arguments.callee

function factorial (num) {
  if (num <=1) {
    return -1;
  } else {
    return num * arguments.callee(num-1)
  }
}

在重寫后的factorial()函數(shù)的函數(shù)體內(nèi),沒有在引用函數(shù)名factorial。這樣,無論引用函數(shù)時使用的是什么名字,都可以保證正常完成遞歸調(diào)用。

var trueFactorial = factorial;

factorial = function () {
  return 0;
};
alert(trueFactorial(5));  //120
alert(factorial(5));  //0

函數(shù)內(nèi)部的另一個特殊對象是this,引用的是函數(shù)據(jù)以執(zhí)行的環(huán)境對象——或者可以說是this值(擋在網(wǎng)頁的全局作用域中調(diào)用函數(shù)時,this對象引用的就是window)。

window.color = "red";
var o = {color: "blue"};

function sayColor () {
  alert(this.color);
}
sayColor();  //"red"
o.syaColor = sayColor;
o.sayColor();  //"blue"

請牢記,函數(shù)的名字僅僅是一個包含指針的變量而已。因此,即使是在不同的環(huán)境中執(zhí)行,全局的sayColor()函數(shù)與o.sayColor()指向的仍然是同一個函數(shù)。

ECMAScript 5 也規(guī)范化了另一個函數(shù)對象的屬性:caller。這個屬性中保存著調(diào)用當(dāng)前函數(shù)的函數(shù)的引用,如果是在全局作用域中調(diào)用當(dāng)前函數(shù),它的值為null

function outer() {
  inner();
}
function inner() {
  alert(inner.caller);
}
outer();

以上代碼會導(dǎo)致警告框中顯示outer()函數(shù)的源代碼。因為outer()調(diào)用了inner(),所以inner.caller就指向outer()。為了實現(xiàn)更松散的耦合,也可以通過arguments.callee.caller來訪問相同的信息。

嚴(yán)格模式下,arguments.callee會導(dǎo)致錯誤。

5.5.5 函數(shù)屬性和方法

ECMAScript 中的函數(shù)是對象,因此函數(shù)也有屬性和方法。每個函數(shù)包含兩個屬性:lengthprototype。其中,length屬性表示函數(shù)希望接收的命名參數(shù)的個數(shù)。

function sayName(name) {
  alert(name);
}
function sum(num1, num2) {
  return num1 + num2;
}
function sayHi() {
  alert("hi");
}

alert(sayName.length);  //1
alert(sum.length);  //2
alert(sayHi.length);  //0

對于ECMAScript 中的引用類型而言,prototype是保存它們所有實例方法的真正所在。換句話說,諸如toString()valueOf()等方法實際上都保持在prototype名下,只不過是通過各自對象的實例訪問罷了。在創(chuàng)建自定義引用類型以及實現(xiàn)繼承時,prototype屬性的作用是極為重要的。
每個函數(shù)都包含兩個非繼承而來的方法:apply()call()。這兩個方法的用途都是在特定的作用域中調(diào)用函數(shù)。實際上等于設(shè)置函數(shù)體內(nèi)this對象的值。首先,apply()方法接收兩個參數(shù):一個是在其中運行函數(shù)的作用域,另一個是參數(shù)數(shù)組。其中,第二個參數(shù)可以是Array的實例,也可以是arguments對象。

function sum(num1, num2) {
  return num1 + num2;
}

function callSum1(num1, num2) {
  return sum.call(this, arguments);  //傳入arguments 對象
}

function callSum2(num1, num2) {
  return sum.apply(this, [num1, num2]);  //傳入?yún)?shù)
}

alert(callSum1(10,10));  //20
alert(callSum2(10,10));  //20

callSum1()在執(zhí)行sum()函數(shù)時傳入了this作為this值(因為是在全局作用域中調(diào)用的,所以傳入的就是window對象)和arguments對象。而callSum2同樣也調(diào)用了sum()函數(shù),但它傳入的則是this和一個參數(shù)數(shù)組。這兩個函數(shù)都會正常執(zhí)行并返回正確的結(jié)果。

在嚴(yán)格模式下,未指定環(huán)境對象而調(diào)用函數(shù),則this值不會轉(zhuǎn)型為window。除非明確把函數(shù)添加到某個對象或者調(diào)用apply()call(),否則this值將是undefined

call()方法與apply()方法的作用相同,它們的區(qū)別僅在于接收參數(shù)的方式不同。對于call()方法而言,第一個參數(shù)是this值沒有變化,變化的是其余參數(shù)都直接傳遞給函數(shù)。即在使用call()方法時,傳遞給函數(shù)的參數(shù)必須逐個列舉出來。

function sum(num1, num2) {
  return num1 + num2;
}

function callSum(num1, num2) {
  return sum.call(this, num1, num2);
}

alert(callSum(10,10));  //20

傳遞參數(shù)并非apply()call()真正的用武之地;它們真正強大的地方是能夠擴充函數(shù)賴以運行的作用域。

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來擴充作用域的最大好處,就是對象不需要與方法有任何耦合關(guān)系。
ECMAScript 5 還定義了一個方法:bind()。這個方法會創(chuàng)建一個函數(shù)的實例,其this值會被綁定到傳給bind()函數(shù)的值。

window.color = "red";
var o = {color: "blue"};

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

每個函數(shù)繼承的toLocaleString()toString()方法始終都返回函數(shù)的代碼。返回代碼的格式則因瀏覽器而異——有的返回的代碼與源代碼中的函數(shù)代碼一樣,而有的則返回函數(shù)代碼的內(nèi)部表示,即由解析器刪除了注釋并對某些代碼作了改動后的代碼。由于存在這些差異,我們無法根據(jù)這兩個方法返回的結(jié)果來實現(xiàn)任何重要功能;不過,這些信息在調(diào)試代碼時倒是很有用。另外一個繼承的valueOf()方法同樣也只有返回函數(shù)代碼。

5.6 基本包裝類型

為了便于操作基本類型值,ECMAScript 還提供了 3 個特殊的引用類型:Boolean,NumberString。這些類型與本章介紹的其他引用類型相似,但同時也具有與各自的基本類型相應(yīng)的特殊行為。實際上,每當(dāng)讀取一個基本類型值的時候,后臺就會創(chuàng)建一個對應(yīng)的基本包裝類型的對象,從而讓我們能夠調(diào)用一些方法來操作這些數(shù)據(jù)。

var s1 = "some text";
var s2 = s1.substring(2);

俺們知道,基本類型值不是對象,因而從邏輯上講它們不應(yīng)該有方法(盡管如我們所愿,它們確實有方法)。其實,為了讓我們實現(xiàn)這種直觀的操作,后臺已經(jīng)自動完成了一系列的處理。當(dāng)?shù)诙写a訪問 s1 時,訪問過程處于一種讀取模式,也就是要從內(nèi)存中讀取這個字符串的值。而在讀取模式中訪問字符串時,后臺都會自動完成下列處理。

  1. 創(chuàng)建String類型的一個實例;
  2. 在實例上調(diào)用指定的方法;
  3. 銷毀這個實例。

可以將以上三個步驟想象成是執(zhí)行了下列ECMAScript代碼。

var s1 = new String("some text");
var s2 = s1.substring(2);
s1 = null;

經(jīng)過此番處理,基本的字符串值就變得跟對象一樣了。而且,上面這三個步驟也分別適用于BooleanNumber類型對應(yīng)的布爾值和數(shù)字值。
引用類型與基本包裝類型的主要區(qū)別就是對象的生存期。使用new操作符創(chuàng)建的引用類型的實例,在執(zhí)行流離開當(dāng)前作用域之前都一直保存在內(nèi)存中。而自動創(chuàng)建的基本包裝類型的對象,則只存在于一行代碼的執(zhí)行瞬間,然后立即銷毀。這意味著我們不能在運行時為基本類型添加屬性和方法。

var s1 = "some text";
s1.color = "red";
alert(s1.color);  //undefined

問題的原因在于第二行創(chuàng)建的String對象在執(zhí)行第三行代碼時已經(jīng)被銷毀了。第三行代碼又創(chuàng)建自己的String對象,而該對象沒有color屬性。
當(dāng)然,可以顯示地調(diào)用BooleanNumberString來創(chuàng)建基本包裝類型的對象。應(yīng)該盡量避免這樣做,因為這種方法做很容易讓人分不清自己是在處理基本類型還是引用類型的值。對基本包裝類型的實例調(diào)用typeof會返回object,而且所有基本包裝類型的對象都會被轉(zhuǎn)換為布爾值true
Object構(gòu)造函數(shù)也會像工廠方法一樣,根據(jù)傳入值的類型返回相應(yīng)基本包裝類型的實例。

var obj = new Object("some text");
alert(obj instanceof String);  //true

把字符串傳給Object構(gòu)造函數(shù),就會創(chuàng)建String的實例;其他類似。
要注意的是,使用new調(diào)用基本包裝類型的構(gòu)造函數(shù),與直接調(diào)用同名的轉(zhuǎn)型函數(shù)是不一樣的。

var value = "25";
var number = Number(value);  //轉(zhuǎn)型函數(shù)
alert(typeof number);  //"number"

var obj = new Number(value);  //構(gòu)造函數(shù)
alert(typeof obj);  //"object"

5.6.1 Boolean 類型

Boolean類型是與布爾值對應(yīng)的引用類型。

var booleanObject = new Boolean(true);

Boolean類型的實例重寫了valueOf()方法,返回基本類型值truefalse;重寫了toString()方法,返回字符串“true”和“false”。用處不大,經(jīng)常造成誤解。其中最常見的問題是在布爾表達(dá)式中使用Boolean對象。

var falseObject = new Boolean(false);
var result = falseObject && true;
alert(result);  //true

var falseValue = false;
result = falseValue && true;
alert(result);  //false

在布爾運算中,false && true等于false。但是布爾表達(dá)式中的所有對象都會被轉(zhuǎn)換為true,因此falseObject對象在布爾表達(dá)式中代表的是true
基本類型與引用類型的布爾值還有兩個區(qū)別。首先,typeof操作符對基本類型返回"boolean",而對引用類型返回"object"。其次,由于Boolean對象是Boolean類型的實例,所以使用instanceof操作符測試Boolean對象會返回true,而測試基本類型的布爾值則返回false

alert(typeof falseObject);  //object
alert(typeof falseValue);  //boolean
alert(falseObject instanceof Boolean);  //true
alert(falseValue instanceof Boolean);  //false

建議永遠(yuǎn)不要使用Boolean對象

5.6.2 Number 類型

Number是與數(shù)字值對應(yīng)的引用類型。要創(chuàng)建Number對象,可以在調(diào)用Number構(gòu)造函數(shù)時向其中傳遞相應(yīng)的數(shù)值。

var numberObject = new Number(10);

Number類型也重寫了valueOf()toLocaleString()toString()方法。重寫后的valueOf()方法返回對象表示的基本類型的數(shù)值,另外兩個方法則返回字符串形式的數(shù)值。在第 3 章中介紹過,可以為toString()方法傳遞一個表示基數(shù)的參數(shù),告訴它返回幾進制的字符串形式。

除了繼承的方法外,Number類型還提供了一些用于將數(shù)值格式化為字符串的方法。其中,toFixed()方法會按照指定的小數(shù)位返回數(shù)值的字符串表示。

var num = 10;
alert(num.toFixed(2));  //"10.00"

如果數(shù)值本身包含的小數(shù)位比指定的還多,那么接近的最大小數(shù)位的值就會舍入。

var num = 10.005;
alert(num.toFixed(2));  //"10.01"

另外可用于格式化數(shù)值的方法是toExponential(),該方法返回以指數(shù)表示法(也稱 e 表示法)表示的數(shù)值的字符串形式。,接受一個參數(shù),同樣也是指定輸出結(jié)果中的小數(shù)位數(shù)。

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

如果你想得到表示某個數(shù)值的最合適的格式,就應(yīng)該使用toPrecision()方法。
對于一個數(shù)值來說,toPrecision()方法可能會返回固定大小 (fixed)格式,也可能返回指數(shù)(exponential)格式;具體規(guī)則是看哪種格式最合適。該方法接收一個參數(shù),即表示數(shù)值的所有數(shù)字的位數(shù)(不包括指數(shù)部分)。

var num = 99;
alert(num.toPrecision(1));  //"1e+2"
alert(num.toPrecision(2));  //"99"
alert(num.toPrecision(3));  //"99.0"

不建議直接實例化Number類型,其他與Boolean對象一樣。

5.6.3 String 類型

String類型是字符串的對象包裝類型,可以像下面這樣使用String構(gòu)造函數(shù)來構(gòu)造。

var stringObject = new String("hello world");

String對象的方法也可以在所有基本的字符串值中訪問到。其中,繼承的valueOf()toLocaleString()toString()方法,都返回對象所表示的基本字符串值。
String類型的每個實例都有一個length屬性,表示字符串中包含多個字符。

var stringValue = "hello world";
alert(stringValue.length);  //11

即使字符串中包含雙字節(jié)字符(不是占一個字節(jié)的 ASCII 字符),每個字符也仍然算一個字符。

  1. 字符方法
    兩個用于訪問字符串中特定字符的方法是:charAt()charCodeAt()。這倆方法都接收一個參數(shù),即基于0的字符位置。其中,charAt()方法以單字符字符串的形式返回給定位置的那個字符。
var stringValue = "hello world";
alert (stringValue.charAt(1));  //"e"

如果你想得到的不是字符而是字符編碼。

var stringValue = "hello world";
alert(stringValue.charCodeAt(1));  //輸出“101”

在支持的瀏覽器中,可以使用方括號加數(shù)字索引來訪問字符串中的特定字符。

var stringValue = "hello world";
alert(stringValue[1]);  //"e"
  1. 字符串操作方法
    concat()用于將一個或多個字符串拼接起來,返回拼接得到的新字符串。
var stringValue = "hello";
var result = stringValue.concat(" world");
alert(result);  //"hello world"
alert(stringValue);  //"hello"

concat方法可以接收任意多個參數(shù),也就是說,可以通過它拼接任意多個字符串。

var stringValue = "hello";
var result = stringValue.concat(" world", "!");
alert(result);  //"hello world!"
alert(stringValue);  //"hello"

雖然concat()是專門用來拼接字符串的方法,但實踐中使用更多的還是加號操作符(+)。
ECMAScript 提供了三個基于子字符串創(chuàng)建新字符串的方法:slice()substr()substring()。這三個方法都會返回被操作字符串的一個子字符串,而且也都接受一或兩個參數(shù)。第一個參數(shù)指定子字符串的開始位置,第二個參數(shù)(在指定的情況下)表示子字符串到哪里結(jié)束。具體來說,slice()substring()的第二個參數(shù)指定的是字符串最后一個字符后面的位置。而substr()的第二個參數(shù)指定的則是返回的字符個數(shù)。如果沒有傳遞第二個參數(shù),則將字符串的長度作為結(jié)束位置。這些方法同樣也不會修改字符串本身的值。

var s = "hello world";
alert(s.slice(3));  //"lo world"
alert(s.substring(3));  //"lo world"
alert(s.substr(3));  //"lo world"
alert(s.slice(3, 7));  //"lo w"
alert(s.substring(3, 7));  //"lo w"
alert(s.substr(3, 7));  //"lo worl"

在傳遞給這些方法的參數(shù)是負(fù)值的情況下,它們的行為就不盡相同了。其中,slice()方法會將傳入的負(fù)值與字符串的長度相加,substr()方法會將負(fù)的第一個參數(shù)加上字符串的長度,而將負(fù)的第二個參數(shù)轉(zhuǎn)換為 0。最后,substring()方法會把所有負(fù)值參數(shù)都轉(zhuǎn)換為 0。substring()方法會將較小的數(shù)作為開始位置,將較大的數(shù)作為結(jié)束位置。

var s = "hello world";
alert(s.slice(-3));  //"rld";
alert(s.substring(-3));  //"hello world"
alert(s.substr(-3));  //"rld"
alert(s.slice(3, -4));  //"lo w"
alert(s.substr(3, -4));  //"" (空字符串)

IE 的 JavaScript 實現(xiàn)在處理向 substr()方法傳遞負(fù)值的情況時存在問題,它會返回原始的字符串。IE9 修復(fù)了這個問題。

  1. 字符串位置方法
    由兩個可以從字符串中查找子字符串的方法:indexOf()lastIndexOf()。這兩個方法都是從一個字符串中搜索給定的子字符串,然后返回子字符串的位置(如果沒有找到,則返回 -1)。這倆方法區(qū)別在于:indexOf()方法從字符串的開頭向后搜索子字符串,而lastIndexOf()方法是從字符串的末尾向前搜索子字符串。
var s = "hello world";
alert(s.indexOf("o"));  //4
alert(s.lastIndexOf("o"));  //7

這倆方法接收可選的第二個參數(shù),表示從字符串中的那個位置開始搜索。indexOf()會從該參數(shù)指定的位置向后搜索,忽略該位置之前的所有字符;而lastIndexOf()則會從指定的位置向前搜索,忽略該位置之后的所有字符。

var s = "hello world";
alert(s.indexOf("o", 6));  //7
alert(s.indexOf("o", 6));  //4

在使用第二個參數(shù)的情況下,可以通過循環(huán)調(diào)用indexOf()lastIndexOf()來找到所有匹配的子字符串。

var s = "asjfjsjf;sjfjsdfjsdljfsafjsaf";
var position = new Array();
var pos = s.indexOf("a");
while (pos > -1) {
  positions.push(pos);
  pos = s.indexOf("a", pos + 1);
}
alert(positions);
  1. trim() 方法
    這個方法會創(chuàng)建一個字符串的副本,刪除前置及后綴的所有空格,然后返回結(jié)果。
var s = "  hello world "
var trimmed = s.trim();
alert(s);  //"  hello world "
alert(trimmed);  //"hello world"

先進瀏覽器還支持非標(biāo)準(zhǔn)的trimLeft()trimRight()方法,分別用于刪除字符串開頭和末尾的空格。

  1. 字符串大小寫轉(zhuǎn)換方法
    ECMAScript 中涉及字符串大小寫轉(zhuǎn)換的方法有 4 個:toLowerCase()toLocaleLowerCase()toUpperCase()toLocaleUpperCase()

  2. 字符串的模式匹配方法
    第一個方法就是match(),在字符串上調(diào)用這個方法,本質(zhì)上與調(diào)用RegExpexec()方法相同。match()方法只接受一個參數(shù),要么是一個正則表達(dá)式,要么是一個RegExp對象。

var text = "cat, bat, sat, fat";
var pattern = /.at/;
var matches = text.match(pattern);
alert(matches.index);  //0  
alert(matches[0]);  //"cat"
alert(pattern.lastIndex);  //0

另一個用于查找模式的方法是search()。這個方法的唯一參數(shù)與match()方法的參數(shù)相同:由字符串或RegExp對象指定的一個正則表達(dá)式。search()方法返回字符串中第一個匹配項的索引;如果沒有找到匹配項,則返回 -1。而且,search()方法始終是從字符串開頭向后查找模式。

var text = "cat, bat, sat, fat";
var pos = text.search(/at/);
alert(pos);  //1

為了簡化替換子字符串的操作,ECMAScript 提供了replace()方法。這個方法接受兩個參數(shù):第一個參數(shù)可以是一個RegExp對象或者一個字符串(這個字符串不會被轉(zhuǎn)換成正則表達(dá)式),第二個參數(shù)可以是一個字符串或者一個函數(shù)。如果第一個參數(shù)是字符串,那么只會替換第一個字符串,要想替換所有子字符串,唯一的辦法就是提供一個正則表達(dá)式,而且要指定全局標(biāo)志。

var text = "cat, bat, sat, fat";
var result = text.replace("at", "ond");
alert(result);  //"cound, bat, sat, fat"
result = text.replace(/at/g, "ond");
alert(result);  //"cond, bond, aond, fond"

replace()方法的第二個參數(shù)也可以是一個函數(shù)。在只有一個匹配項的的情況下,會向這個函數(shù)傳遞 3 個參數(shù):模式的匹配項,模式匹配項在字符串中的位置和原始字符串。在正則表達(dá)式中定義了多個捕獲組的情況下,傳遞給函數(shù)的參數(shù)依次是模式的匹配項,第一個捕獲組的匹配項,第二個捕獲組的匹配項。。。,但最后兩個參數(shù)仍然分別是模式的匹配項在字符串中的位置和原始字符串。這個函數(shù)應(yīng)該返回一個字符串,表示應(yīng)該被替換額匹配項使用函數(shù)作為replace()方法的第二個參數(shù)可以實現(xiàn)更加精細(xì)的替換操作

function htmlEscape(text) {    return text.replace(/[<>"&]/g, function(match,pos,originalText) {        switch(match) {            case "<":                return "<";            case ">":                return ">";            case "&":                return "&";            case "\*":                return """;        }    });}

最后一個與模式匹配有關(guān)的方法是split(),這個方法可以基于指定的分隔符將一個字符串分割成多個子字符串,并將結(jié)果放在一個數(shù)組中。分隔符可以是字符串,也可以是一個RegExp對象。split()方法可以接受可選的第二個參數(shù),用于指定數(shù)組的大小,以確保返回的數(shù)組不會超過既定大小。

var colorText = "red,blue,green,yellow";
var colors1 = colorText.split(",");  //["red","blue","green", "yellow"]
var colors2 = colorText.split(",", 2);  //["red", "blue"]
var colors3 = colorsText.split(/[^\,]+/);  //["", ",", ",",",", ""] 
  1. localeCompare() 方法
    與操作字符串有關(guān)的最后一個方法是localeCompare(),這個方法比較兩個字符串,并返回下列值中的一個:
  • 如果字符串在字母表中應(yīng)該排在字符串參數(shù)之前,則返回一個負(fù)數(shù)(大多數(shù)情況下是 -1, 具體的值要視實現(xiàn)而定);
  • 如果字符串等于字符串參數(shù),則返回 0;
  • 如果字符串在字母表中應(yīng)該排在字符串參數(shù)之后,則返回一個正數(shù)(大多數(shù)情況下是 1,具體的值同樣要視實現(xiàn)而定)。
var s = "yellow";
alert(s.localeCompare("brick"));  //1
alert(s.localeCompare("yellow"));  //0
alert(s.localeCompare("zoo"));  //-1

最好采用函數(shù)判斷并規(guī)定返回數(shù)值。

  1. fromCharCode() 方法
    String構(gòu)造函數(shù)本身還有一個靜態(tài)方法:fromCharCode()。這個方法的任務(wù)是接收一或多個字符編碼,然后將他們轉(zhuǎn)換成一個字符串。從本質(zhì)上看,這個方法與實例方法charCodeAt()執(zhí)行的是相反的操作。
alert(String.fromCharCode(104, 101, 108, 108, 111));  //"hello"
  1. HTML 方法
    盡量不使用這些方法。故不列出。

5.7 單體內(nèi)置對象

5.7.1 Global 對象

不屬于任何其他對象的屬性和方法,最終都是它的屬性和方法。

  1. URI 編碼方法
    encodeURI()encodeURIComponent()方法可以對 URI 進行編碼,以便發(fā)送給瀏覽器。有效的 URI 中不能包含某些字符,例如空格。
    其中,encodeURI()主要用于整個URI(例如,http://www.baidu.com/illegal value.htm),而encodeURIComponent()主要用于對某一段(例如illegal value.htm)進行編碼。它們的主要區(qū)別在于,encodeURI()不會對本身屬于 URI 的特殊字符進行編碼,例如冒號,正斜杠,問號和井字號;而encodeURIComponent()則會對它發(fā)現(xiàn)的任何非標(biāo)準(zhǔn)字符進行編碼。
    對應(yīng)的方法為decodeURI()decodeURIComponent()

一般來說,使用encodeURIComponent()方法更多,因為在實踐中更常見的是對查詢字符串參數(shù)而不是對基礎(chǔ) URI 進行編碼。

  1. eval() 方法
    非常危險,略。
  2. Global 對象的屬性
    下表列出了所有屬性
屬性 說明
undefined 特殊值
NaN 特殊值
Infinity 特殊值
Object 構(gòu)造函數(shù)
Array 構(gòu)造函數(shù)
Function 構(gòu)造函數(shù)
Boolean 構(gòu)造函數(shù)
String 構(gòu)造函數(shù)
Number 構(gòu)造函數(shù)
Date 構(gòu)造函數(shù)
RegExp 構(gòu)造函數(shù)
Error 構(gòu)造函數(shù)
EvalError 構(gòu)造函數(shù)
RangeError 構(gòu)造函數(shù)
ReferenceError 構(gòu)造函數(shù)
SyntaxError 構(gòu)造函數(shù)
TypeError 構(gòu)造函數(shù)
URIError 構(gòu)造函數(shù)
  1. window 對象
    ECMAScript 雖然沒有指出如何直接訪問Global對象,但Web瀏覽器都是將這個全局對象作為window對象的一部分加以實現(xiàn)的。因此,在全局作用域中聲明的所有變量和函數(shù),就都成為了widnow對象的屬性。

5.7.2 Math 對象

Math對象提供了輔助完成數(shù)學(xué)計算的屬性和方法。
1.Math 對象的屬性

屬性 說明
Math.E 自然對數(shù)的底數(shù),即常量e的值
Math.LN10 10的自然對數(shù)
Math.LN2 2的自然對數(shù)
Math.LOG2E 以2為底e的對數(shù)
Math.LOG10E 以10為底e的對數(shù)
Math.PI π的值
Math.SQRT1_2 1/2 的平方根(即2的平方根的倒數(shù))
Math.SQRT2 2的平方根

2.min() 和 max() 方法
還包含許多方法,用于輔助完成簡單和復(fù)雜的數(shù)學(xué)計算。
其中,min()和'max()'方法用于確定一組數(shù)值中的最小值和最大值。這兩個方法都可以接收任意多個數(shù)值參數(shù)。

var max =Math.max(3, 54, 32, 16);
alert(max);  //54
var min = Math.min(3, 54, 32, 16);
alert(min);  //3

要找到數(shù)組中的最大或最小值,可以像下面這樣使用apply()方法。

var value = [1, 2, 3, 4, 5, 6];
var max = Math.max.apply(Math, values);

這個技巧的關(guān)鍵是把Math對象作為apply()的第一個參數(shù),從而正確地設(shè)置this值。然后,可以將任何數(shù)組作為第二個參數(shù)。

3.舍入方法
將小數(shù)值舍入為整數(shù)的幾個方法:Math.ceil()Math.floor()Math.round()
這三個方法分別遵循下列舍入規(guī)則:

  • Math.ceil()執(zhí)行向上舍入
  • Math.floor()執(zhí)行向下舍入
  • Math.round()執(zhí)行標(biāo)準(zhǔn)舍入,即四舍五入

4.random()方法
Math.random()方法返回介于 0 和 1 之間隨機一個隨機數(shù),不包括 0 和 1。
Math.random()從某個整數(shù)范圍內(nèi)隨機選擇一個值。

值 = Math.floor(Math.random() * 可能值的總數(shù) + 第一個可能的值)

如果想要選擇一個介于 2 到 10 之間的值

var num = Math.floor(Math.random() * 9 +2);

多數(shù)情況下,可以通過一個函數(shù)來計算可能值的總數(shù)和第一個可能的值。

function selectFrom(lowerValue, upperValue) {
  var choices = upperValue - lowerValue + 1;
  return Math.floor(Math.random() * choices + lowerValue);
}
var num = selectFrom(2, 10);
alert(num);  //介于 2 和 10 之間 (包括 2 和 10)的一個數(shù)值

5.其他方法
下表列出了沒有介紹到的方法

方法 說明
Math.abs(num) 返回絕對值
Math.exp(num) 返回Math.E的num次冪
Math.log(num) 返回num的自然對數(shù)
Math.pow(num, power) 返回num的power次冪
Math.sqrt(num) 返回num的平方根
Math.acos(x) 返回x的反余弦值
Math.asin(x) 返回x的反正弦值
Math.atan(x) 返回x的反正切值
Math.atan2(y,x) 返回y/x的反正切值
Math.cos(x) 返回x的余弦值
Math.sin(x) 返回x的正弦值
Math.tan(x) 返回x的正切值

5.8 小結(jié)

對象在 JavaScript 中被稱為引用類型的值,而且有一些內(nèi)置的引用類型可以用來創(chuàng)建特定的對象。

  • 引用類型與傳統(tǒng)面向?qū)ο蟪绦蛟O(shè)計中的類相似,但實現(xiàn)不同;
  • Object是一個基礎(chǔ)類型,其他所有類型都從Object繼承了基本的行為;
  • Array類型是一組值的有序列表,同時還提供了操作和轉(zhuǎn)換這些值得功能;
  • Date類型提供了有關(guān)日期和時間的信息,包括當(dāng)前日期和時間以及相關(guān)計算功能;
  • RegExp類型提供了最基本的和一些高級的正則表達(dá)式功能。

函數(shù)實際上是Function類型的實例,因此函數(shù)也是對象;由于函數(shù)是對象,所以函數(shù)也擁有方法。
因為有了基本包裝類型,所以JavaScript中的基本類型可以被當(dāng)作對象來訪問。三種基本包裝類型分別是:BooleanNumberString。以下是它們共同的特征:

  • 每個包裝類型都映射到同名的基本類型;
  • 在讀取模式下訪問基本類型值時,就會創(chuàng)建對應(yīng)的基本包裝類型的一個對象,從而方便了數(shù)據(jù)操作;
  • 操作基本類型值的語句一經(jīng)執(zhí)行完畢,就會立即銷毀新創(chuàng)建的包裝對象。

在所有代碼執(zhí)行之前,作用域中就已經(jīng)存在兩個內(nèi)置對象:GlobalMath。Web 瀏覽器實現(xiàn)了承擔(dān)該角色的window對象。全局變量和函數(shù)都是Global對象的屬性。Math對象提供了很多屬性和方法,用于輔助完成復(fù)雜的數(shù)學(xué)計算任務(wù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,250評論 6 530
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 97,923評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,041評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,475評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,253評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,801評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,882評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,023評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,530評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,494評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,639評論 1 366
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,177評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 43,890評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,289評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,552評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,242評論 3 389
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,626評論 2 370

推薦閱讀更多精彩內(nèi)容