JS基礎——引用型別
引用型別的值(物件)是引用型別的一個例項,引用型別是一種資料結構,用於將資料和功能組織在一起。引用型別有時候也被稱為物件定義,因為他們描述的是一類物件所具有的屬性和方法。物件是某個特定引用型別的例項,新物件是使用new操作符後跟一個建構函式來建立。
varperson = new Object();
5.1 Object型別
1. 建立Object例項
建立Object例項的方式有兩種:
(1)使用new操作符後跟Object建構函式
var person = new Object();
person.name = "Chris";
person.age = 22;
(2)使用物件字面量 表示法
var person = {
name : "Chris",
age : 22
};
注意:
1) 在物件字面量中,使用逗號來分隔不同的屬性,但在最後一個屬性後面不能新增逗號。否則在一些早 版本瀏覽器中導致錯誤。
2)在使用物件字面量語法時,屬性名也可以使用字串;
3)使用物件字面量語法時,如果留空其花括號,則可以定義只包含預設屬性和方法的物件,如下:
var person = {};
person.name = "Chris";
person.age = 22;
2. 訪問物件屬性
(1)點表示法
alert(person.name);//"Chris"
(2)方括號表示法
alert(person["name"]);//"Chris"
注意:1)方括號表示法的主要優點是可以通過變數來訪問屬性;
var propertyName = "name";
alert(person[propertyName]);//"Chris"
2)如果屬性名中包含會導致語法錯誤的字元,或者屬性名使用的是關鍵字或者保留字,也可以使用方括號表示法;
person["first name"] = "Chris";
因為"first name"中包含一個空格,所以不能讓使用點表示法來訪問它們,然而,屬性名中是可以包含非字母非數字的,這時候就可以使用方括號表示法來訪問它們;
3)通常,除非必須使用變數來訪問屬性,否則建議使用點表示法。
5.2 Array型別
1、與其他語言不同的是:
(1)ECMScript陣列的每一項可以儲存任何型別的資料;
(2)ECMScript陣列的大小是可以動態調整的,即可以隨著資料的新增自動增長以容納新增資料;
2、建立陣列的基本方式有兩種:
(1)使用Array建構函式;
var colors = new Array();
(2)使用陣列字面量表示法,陣列字面量由一對包含陣列項的方括號表示,多個數組之間以逗號隔開;
var colors = ["red", "blue", "yellow"];
3、在讀取和設定陣列的值時,要使用方括號並提供相應值的基於0的數字索引;
var colors = ["red", "blue", "green"] //定義一個字串陣列
alert(colors[0]); //顯示第一項
colors[2] = "black";//修改第三項
colors[3] = "brown";//新增第四項
4、陣列的項數儲存在其
length
屬性中,這個屬性始終會返回0或更大的值;
var colors = ["red", "blue", "green"]; //定義一個字串陣列
alert(colors.length);//3
5、通過設定陣列的length屬性,可以從陣列的末尾移除項或者向陣列中新增新項;
var colors = ["red", "blue", "green"] //定義一個字串陣列
colors.length = 2;
alert(colors[2]);//undefined(移除項)
該例中的陣列colors一開始有3個值,將其length屬性設定為2會移除最後一項(位置為2的那一項),結果再訪問colors[2]就會顯示undefined。如果將其length屬性設定為大於陣列項數的值,則新增的每一項都回去的undefined值;
var colors = ["red", "blue", "green"] //定義一個字串陣列
colors.length = 4;
alert(colors[3]);//undefined(新增項)
利用length屬性也可以方便地在陣列末尾新增新項;
var colors = ["red", "blue", "green"] //定義一個字串陣列
colors[colors.length] = "black";//(在位置3)新增一種顏色
colors[colors.length] = "brown";//(在位置4)再新增一種顏色
當把一個值放在超出當前陣列大小的位置上時,陣列就會重新計算其長度值,即長度值等於最後一項的索引加1。
1. 檢測陣列
(1)對於一個網頁或者有個全域性作用域而言,使用
instanceof
操作符就能確定某個物件是不是陣列;
if (value instanceof Array) {
//對陣列執行某些操作
}
(2)
Array.isArray()
方法的目的是最終確定某個值到底是不是陣列,而不管它是在哪個全域性執行環境中建立的。
if (Array.isArray(value)) {
//對陣列執行某些操作
}
2. 轉換方法
所有物件都具有
toLocaleString()
、toString()
和
valueOf()
方法。其中,呼叫valueOf()返回的還是陣列本身,而呼叫陣列的toString()方法會返回有陣列中每個值的字串形式拼接而成的一個以逗號分隔的字串;
toLocalString()方法經常會返回與toString()和valueOf()方法相同的值,但也不總是如此。
陣列繼承的toLocaleString()、toString()和valueOf()方法,在預設情況下都會以逗號分隔的字串的形式返回陣列項,而如果使用
join()
方法,則可以使用不同的分隔符來構建這個字串(將陣列轉化為字串
)。join()方法只接收一個引數,即用作分隔符的字串,然後返回包含所有陣列項的字串.如果不給join()方法傳入任何值,或者給它傳入undefined,則使用逗號作為分隔符。
var colors = ["red", "green", "blue"];
alert(colors.join(","));//red,green,blue
alert(colors.join("||"));//red||green||blue
3. 棧方法
棧是一種LIFO(Last-In-First-Out,先進後出)的資料結構,也就是最新新增的項最早被移除。而棧中項的插入(叫做推入 )和移除(叫做彈出 ),只發生在一個位置——棧的頂部。
push()
方法可以接收任意數量的引數,把它們逐個新增到陣列末尾,並返回修改後陣列的長度;
pop()
方法從陣列末尾移除最後一項,減少陣列的length值,然後返回移除的項;
var colors = new Array();//建立一個數組
var count = colors.push("red", "green");//推入兩項
alert(count);//2
var item = colors.pop(); //取得最後一項
alter(item);//"green"
alter(colors.length); //1
4. 佇列方法
佇列資料結構的訪問規則是FIFO(First-In-First-Out,先進先出)。佇列在列表的末端新增項,從列表的前端移除項;
(1)
shift()
方法,它能夠移除陣列中的第一項並返回該項,同時將陣列長度減1(刪除第一項);
(2)
unshift()
方法,它能在陣列前端新增任意個項並返回新陣列的長度。
(3)結合使用shift()和push()方法,可以像使用佇列一樣使用陣列;(末端新增項,前端移除項)
var colors = new Array(); //建立一個數組
var count = colors.push("red", "green"); //推入兩項
alter(count);//2
count = colors.push("black");//末端推入另一項
var item = colors.shift();//取得第一項
alter(item); //"red"
alter(colors.length);//2
(4)同時使用unshift()和pop()方法,可以從相反的方向來模擬佇列;(前端新增項,末端移除項)
var colors = new Array(); //建立一個數組
var count = colors.push("red", "green"); //推入兩項
alter(count);//2
count = colors.unshift("black");//前端推入另一項
var item = colors.pop();//取得最後一項
alter(item); //"green"
alter(colors.length);//2
(1)陣列中已經存在的兩個可以直接用重排序的方法:
reverse()
和
sort()
方法
reverse()方法會反轉陣列項的順序;
在預設情況下,sort()方法按升序排列陣列項,sort()方法會呼叫每個陣列項的toString()轉型方法,然後比較得到字串,已確定如何排序,即使陣列中的每一項都是數值,sort()方法比較的也是字串。
(2)比較函式(P93)
6. 操作方法
(1)
concat()
方法可以基於當前陣列中的所有項建立一個新的陣列
(2)
slice()
方法能夠基於當前陣列中的一個多個項建立一個新的陣列。slice()方法可以接收一個或者兩個引數,即要返回項的起始和結束位置。在只有一個引數的情況下,slice()方法返回從該引數指定位置開始到當前陣列末尾的所有項;如果有兩個引數,該方法返回起始和結束位置之間的項——但不包括結束位子的項。注意,slice()方法不會影響原始陣列。
var colors = ["red", "green", "blue", "yellow","purple"];
var colors2 = colors.silce(1);
var colors3 = colors.slice(1,4);
alter(colors2); //green,blue,yellow,purple
alter(colors3); //green,blue,yellow
注意:
1)如果slice方法的引數中有一個附屬,則用陣列長度加上該數來確定相應的位置;
2)如果結束位置小於起始位置,則返回空陣列
(3)
splice()
方法的主要用途是向陣列的中部插入項
1)刪除 :可以刪除任意數量的項,只需指定2個引數:splice(要刪除的第一項的位置,要刪除的項數)
2)插入 :可以向指定位置插入任意數量的項,只需提供3個引數splice(起始位置,要刪除的項數,要插入的項)
3)替換 :可以向指定位置插入任意數量的項,且同時刪除任意數量的項,只需指定3個引數
splice(起始位置,要刪除的項數,要插入的任意數量的項),插入的項數不必與刪除的項數相等;
var colors = ["red", "green", "blue"];
var removed = colors.splice(0,1)//刪除第一項
alter(colors);//green,blue
alter(removed); //red,返回的陣列中只包含一項
removed = colors.splice(1,0,"yellow","orange");//從位置1開始插入兩項
alter(colors);//green,yellow,orange,blue
alter(removed);//返回的是一個空陣列
removed = colors.splice(1,1,"red","purple");//插入兩項,刪除一項
alter(colors); //green,red,purple,orange,blue
alter(removed); //yellow,返回的陣列中只包含一項
7. 位置方法
indexOf()
和
lastIndexOf()
,這兩個方法都接收兩個引數:要查詢的項和(可選的)表示查詢起點位置的索引。其中,indexOf()方法從陣列的開頭(位置0 )開始向後查詢。LastIndexOf()方法則從陣列的末尾向前查詢。這兩個方法都返回要查詢的項在陣列中的位置,或者在沒有找到的情況下返回-1.
var numbers = [1,2,3,4,5,4,3,2,1];
alter(numbers.indexOf(4));//3
alter(numbers.lastIndexOf(4));//5
alter(numbers.indexOf(4,4));//5
alter(numbers.lastIndexOf(4,4));//3
8. 迭代方法
每個方法都接收兩個引數:要在每一項執行的函式和(可選的)執行該函式的作用域物件。傳入這些方法中的函式會接收三個引數:陣列項的值、該項在陣列中的位置和陣列物件本身。
-
every()
:對陣列中的每一項執行給定函式,如果該函式對每一項都返回true,則返回true; -
filter()
:對陣列中的每一項執行給定函式,返回該函式會返回true的項組成的陣列; -
forEach()
:對陣列中的每一項執行給定函式,該方法沒有返回值; -
map()
:對陣列中的每一項執行給定函式,返回每次函式呼叫的結果組成的陣列; -
some()
:對陣列中的每一項執行給定函式,如果該函式對任一項返回true,則返回true。
注意:對every()來說,傳入的函式必須對每一項都返回true,這個方法才返回true;而some()方法則是隻要傳入的函式對陣列中的某一項返回true,就會返回true。
9. 歸併方法
ECMAScript5新增了兩個歸併陣列的方法:reduce()和reduceRight()。這兩個方法都會迭代陣列的所有項,然後構建一個最終返回值。其中reduce()方法從陣列的第一項開始,逐個遍歷到最後。而reduceRight()則從陣列的最後一項開始,向前遍歷到第一項。
以上兩種方法都接收兩個引數:在每一項呼叫的函式、作為歸併基礎的初始值。
傳給reduce()和reduceRight()的函式接收四個引數:前一個值、當前值、項的索引和陣列物件。這個函式返回的任何值都會作為第一個引數自動傳給下一項。以第一次迭代發生在陣列的第二項上,因此第一個引數是陣列的第一項,第二個引數就是陣列的第二項。
var values = [1,2,3,4,5];
var sum = values.reduce(function(prev, cur, index, array){
return prev + cur;
});
alter(sum); //15
5.3 Date型別
要建立一個日期物件,使用new操作符和Date建構函式即可
var now = new Date();
//在呼叫Date建構函式而不傳遞引數的情況下,新建立的物件自動獲得當前日期和時間
如果想根據特定的日期和時間建立日期物件,必須傳入該日期的毫秒數。或者使用
Date.parse()
和
Date.UTC()
;
Date.parse()
方法接收一個表示日期的字串引數,然後嘗試根據這個字串返回相應日期的毫秒數;如果傳入Date.parse()方法的字串不能表示日期,那麼它會返回NaN;如果直接將表示日期的字串傳遞給Date建構函式,也會在後臺呼叫Date.parse()。
Date.UTC()
方法同樣也返回表示日期的毫秒數,Date.UTC()的引數分別是年份、基於0的月份,月中的哪一天(1到31)、小時數(0到23)、分鐘、秒以及毫秒數。在這些引數中,只有年和月是必需的
Date.now()
方法,返回表示呼叫這個方法時的日期和時間的毫秒數。
1. 繼承的方法
Date型別也重寫了toLocaleString()、toString()和valueOf()方法。
- Date型別的toLocaleString()方法會按照與瀏覽器設定的時區相適應的格式返回日期和時間。(大致意味時間格式中會包含AM或PM,但不會包含時區資訊);
- Date型別的toString()方法則通常返回帶有時區資訊的日期和時間,其中時間一般以軍用時間表示;
- Date型別的valueOf()方法則根本不返回字串,而是返回日期的毫秒錶示。因此,可以方便使用比較操作符(小於或大於)來比較日期值。
2. 日期格式化方法
- toDateString()——以特定於實現的格式顯示星期幾、月、日和年;
- toTimeString()——以特定於實現的格式顯示時、分、秒和時區;
- toLocaleDateString()——以特定於地區的格式顯示星期幾、月、日和年;
- toLocaleTimeString()——以特定於實現的格式顯示時、分、秒和時區;
- toUTCString()——以特定於實現的格式完整的UTC日期;
3. 日期/時間元件方法(P102)
5.4 RegExp型別
RegExp型別是用來支援正則表示式:
(1)第一種建立正則表示式的方法如下:
var expression = / pattern / flags;
其中的模式(pattern )部分可以是任何簡單或複雜的正則表示式,可以包含字元類、限定符、分組、向前查詢以及反向引用。
每個正則表示式都可以帶有一個或者多個標誌(flags ),用以標明正則表示式的行為。正則表示式的匹配模式支援下列3個標誌:
- g:表示全域性(global)模式,即模式將被應用於所有字串,而非在發現第一個匹配項時立即停止;
- i:表示不區分大小寫(case-insensitive)模式,即在確定匹配項時忽略模式與字串的大小寫;
- m:表示多行(multiline)模式,即在到達一行文字末尾時還會繼續查詢下一行是否存在與模式匹配的項
模式中使用的所有元字元都必須轉義。正則表示式中的元字元包括:( [ {^ $ | ) ? * + . ] }
(2)另一種建立正則表示式的方式是使用RegExp函式,它接收兩個引數:一個是要匹配的字串模式,另一個是可選的標誌字串。
//匹配第一個"bat"或"cat",不區分大小寫
var pattern1 = /[bc]at/i;//使用第一種方法建立
var pattern2 = new RegExp("[bc]at","i"); //使用RegExp函式實現
由於RegExp建構函式的模式引數是字串,所以在某些情況下要對字串進行雙重轉義。
1. RegExp例項屬性
- global:布林值,表示是否設定了g標誌;
- ignoreCase:布林值,表示是否設定了i標誌;
- lastIndex:整數,表示開始搜尋下一個匹配項的字元位置,從0算起。
- multiline:布林值,表示是否設定了m標誌;
- source:正則表示式的字串表示,按照字面量形式而非傳入建構函式的字串模式返回。
- source屬性儲存的是規範形式的字串,即字面量形式所用的字串。
2. RegExp例項方法
正則表示式的第一個方法是exec()
連結描述
: 接收一個引數,即要應用模式的字串,然後返回包含第一個匹配資訊的陣列;或者在沒有匹配項的情況下返回null。exec() 方法還返回兩個屬性。index
屬性宣告的是匹配文字的第一個字元的位置(匹配項在字串中的位置)。input
屬性則存放的是被檢索的字串 string(表示應用正則表示式的字串)。
對於exec()方法而言,即使在模式中設定了全域性標誌(g),他每次也只會返回一個匹配項。在不設定全域性標誌的情況下,在同一個字串上多次呼叫exec()將始終返回第一個匹配項的資訊,而在設定全域性變數的情況下,每次呼叫exec()則都會在字串中繼續查詢新匹配項。
正則表示式的第二個方法是test()
連結描述
:它接受一個字串引數,如果字串 string 中含有與RegExpObject 匹配的文字,則返回true,否則返回false
3. RegExp建構函式屬性
-
input:最近一次要匹配的字串
["
$_
"] -
lastMatch:最近一次與整個正則表示式匹配的字串
["
$&
"] -
lastParen:最近一次匹配的捕獲組
["
$+
"] - leftContext:input字串中lastMatch之前的文字["`$"]
-
rightContext:input字串中lastMatch之後的文字
["
$'
"] -
multiline:布林值,表示是否所有表示式都使用多行模式
["
$*
"]
var text = "this has been a short summer";
var pattern = /(.)hort/g;
if(pattern.test(text)){
alter(RegExp.input);//this has been a short summer
alter(RegExp.leftContext);//this has been
alter(RegExp.rightContext);//summer
alter(RegExp.lastMatch);//short
alter(RegExp.lastParen);//a
alter(RegExp.multiline);//false
}
注意:以上使用的長屬性名都可以用相應的短屬性名來代替,不過短屬性名不是有效的ECMAScript識別符號,因此必須通過方括號語法來訪問它們。
var text = "this has been a short summer";
var pattern = /(.)hort/g;
if(pattern.test(text)){
alter(RegExp.$_);//this has been a short summer
alter(RegExp["$
"]);//this has been`
alter(RegExp["$'"]);//summer
alter(RegExp["$&"]);//short
alter(RegExp["$+"]);//a
alter(RegExp["$*"]);//false
}
4. 模式的侷限性(P109)
5.5 Function型別
1. 沒有過載(深入理解)
2. 函式宣告與函式表示式 3. 作為值的函式 4. 函式的內部屬性
在函式內部,有兩個特殊的物件:
arguments
和
this
(1)arguments是一個類陣列物件,包含著傳入函式中的所有引數,它的主要用途是儲存函式引數。這個物件還有一個名叫
callee
的屬性,該屬性是一個指標,指向擁有這個arguments物件的函式。
function factorial(num) {
if (num<=1) {
return 1;
} else {
rerurn num*factorial(num-1);
}
}
轉變為
function factorial(num) {
if (num<=1) {
return 1;
} else {
rerurn num*arguements.callee(num-1);
}
}
在這個重寫後的factorial()函式的函式體內,沒有再引用函式名factorial。這樣,無論引用函式時使用的是什麼名字,都可以保證正常完成遞迴呼叫。
(2)函式內部的另一個特殊物件是this。this引用的是函式執行的環境物件(當在網頁的全域性作用域中呼叫函式時,this物件引用的就是window)
!函式的名字僅僅是一個包含指標的變數而已
EMAScript也規範了另一個函式物件的屬性:
caller
這個屬性儲存著呼叫當前函式的函式的引用
5. 函式屬性和方法
每個函式都包含兩個屬性:
length
和
prototype
(1)length屬性表示函式希望接收的命名引數的個數
(2)prototype屬性是儲存他們所有例項方法的真正所在
(3)每個函式都包含兩個非繼承而來的方法:
apply()
和
call()
,這兩個方法的用途都是在特定的作用域中呼叫函式,實際上等於設定函式體內this物件的值。
apply()方法接收兩個引數:在其中執行的函式的作用域 和 引數陣列
call()方法:第一個引數是this值沒有變化,變化的是其餘引數都直接傳遞給函式。換句話說,在使用call()方法時,傳遞給函式的引數必須逐個列舉出來。
function sum(num1,num2) {
return num1+num2;
}
function callSum1(num1,num2) {
return sum.apply(this,arguments); //傳入arguments物件
}
function callSum2(num1,num2) {
return sum.apply(this,[num1,num2]); //傳入陣列
}
function callSum3(num1,num2) {
return sum.call(this,num1,num2); //其餘引數都直接傳遞給函式
}
alter(callSum1(10,10));//20
alter(callSum2(10,10));//20
alter(callSum3(10,10));//20
apply()和call()真正的用武之地在——能夠擴充函式賴以執行的作用域
windows.color = "red";
var o = {color : "blue"};
function sayColor() {
alter(this.color);
}
sayColor();//red
sayColor.call(this);//red
sayColor.call(window); //red
sayColor.call(o); //blue
使用apply()或call()來擴充作用於的最大好處就是,物件不需要與方法有任何耦合關係。
(4)bind()方法。這個方法會建立一個函式的例項,其this值會被繫結到傳給bind()函式的值。
windows.color = "red";
var o = {color : "blue"};
function sayColor() {
alter(this.color);
}
var objectSayColor= sayColor.bind(o);
objectSayColor();//blue
5.6 基本包裝型別
1. Boolean型別
2. Number型別3. String型別
5.7 單體內建物件
1. Global物件
2. Math物件