第三章 ?類型、值和變量
1、存取字符串、數(shù)字或布爾值的屬性時創(chuàng)建的臨時對象稱做包裝對象,它只是偶爾用來區(qū)分字符串值和字符串對象、數(shù)字和數(shù)值對象以及布爾值和布爾對象。
由于字符串不是對象,但是卻有相應(yīng)的屬性,比如length屬性。這時JavaScript就會將字符串通過調(diào)用new String()的方式轉(zhuǎn)換成對象,這個對象繼承了字符串的方法。同時這個對象是一個臨時對象,一旦屬性引用結(jié)束,這個新創(chuàng)建的對象就會銷毀。
2、對象到字符串的轉(zhuǎn)換步驟:
如果對象具有toString()方法,則調(diào)用這個方法。如果它返回一個原始值,JavaScript將這個值轉(zhuǎn)換為字符串,并返回這個結(jié)果。
如果對象沒有toString()方法,或者這個方法并不返回一個原始值,那么JavaScript會調(diào)用valueOf()方法。如果存在這個方法,則JavaScript調(diào)用它。如果返回值是原始值,JavaScript將這個值轉(zhuǎn)換為字符串,并返回結(jié)果。
如果JavaScript無法從以上2個方法獲取一個原始值,這時將拋出一個類型錯誤異常。
3、對象到數(shù)字的轉(zhuǎn)換過程:
如果對象具有valueOf()方法,后者返回一個原始值,則JavaScript將這個原始值轉(zhuǎn)換為數(shù)字并返回這個數(shù)字。
否則,如果對象具有toString()方法,后者返回一個原始值,則將去轉(zhuǎn)換并返回。
否則,拋出類型錯誤異常。(TypeError)
toString()的作用是返回一個反映這個對象的字符串。同時很多類定義了特定版本的該方法。比如,數(shù)組類的toString()方法將每個數(shù)組元素轉(zhuǎn)換為一個字符串,并在元素之間添加逗號后合并成結(jié)果字符串。
valueOf()方法的并未詳細(xì)定義:如果存在任意原始值,它就默認(rèn)將對象轉(zhuǎn)換為表示它的原始值。如果對象是復(fù)合值,就簡單地返回對象本身。
第四章 表達(dá)式和運算符
1、原始表達(dá)式是表達(dá)式的最小單位---不再包含其他表達(dá)式。JavaScript原始表達(dá)式包含常量或直接量、關(guān)鍵字和變量。需要注意一點的是,undefined是全局變量,和null不同,不是關(guān)鍵字。當(dāng)JavaScript代碼中出現(xiàn)了標(biāo)識符,JavaScript會將其當(dāng)做變量去查找它的值。如果變量名不存在,運算結(jié)果為undefined。嚴(yán)格模式中,對不存在的變量進(jìn)行求值會拋出一個引用錯誤。
2、數(shù)組初始化表達(dá)式是通過一對方括號和數(shù)組內(nèi)逗號隔開的列表構(gòu)成。數(shù)組直接量中的列表逗號之間的元素可以省略,這時省略的空位會填充undefined。如;
var array = [1,,,,5]; ?//三個元素是undefined.
數(shù)組直接量的元素列表結(jié)尾處可以留下單個逗號,這時并不會創(chuàng)建一個新的值為undefined的元素。
3、屬性訪問表達(dá)式,在"."和"["之前的表達(dá)式總是會首先計算。如果計算結(jié)果為null或undefined,表達(dá)式就會拋出一個類型錯誤異常,因為這兩個值都不能包含任意屬性。比如:
var obj;
obj.attr? //? Uncaught TypeError: Cannot read property 'attr' of null
4、運算符
delete --> 刪除屬性
typeof -->檢測操作數(shù)類型
void -->返回undefined值
instanceof -->測試對象類
in -->測試屬性是否存在
,-->忽略第一個操作數(shù),返回第二個操作數(shù)
需要注意的是,屬性訪問表達(dá)式和調(diào)用表達(dá)式的優(yōu)先級要比所有運算符都要高。如:
typeof ?my.functions[x](y)
//盡管typeof是優(yōu)先級最高的運算符之一,但typeof是在兩次屬性訪問和函數(shù)調(diào)用之后執(zhí)行的。
一元操作符、賦值和三元條件運算符都具有從右至做的結(jié)合性。比如:
x = ~-y;
w = x = y = z;
q = a?b:c?d:e?f:g;
//等價于一下代碼
x = ~(-y);
w = (x = (y = z));
q = a?b:(c?d:(e?f:g));
1)子表達(dá)式的運算順序
運算符的優(yōu)先級是嚴(yán)格按照規(guī)定,但是并沒有規(guī)定子表達(dá)式的計算過程中的運算順序。
JavaScript總是嚴(yán)格按照從左至右的順序來計算表達(dá)式。例如:
在表達(dá)式w = x + y * z中,將首先計算子表達(dá)式w,然后計算x、y和z。然后,y的值和z的值相乘,再加上x的值,最后將其賦值給表達(dá)式w所指代的變量或?qū)傩浴?/p>
5、算術(shù)表達(dá)式
算術(shù)運算符進(jìn)行運算時,所有無法轉(zhuǎn)換為數(shù)字的操作符都轉(zhuǎn)換為NaN值。如果操作數(shù)或者轉(zhuǎn)換結(jié)果為NaN值,算術(shù)運算的結(jié)果也為NaN。求余結(jié)果的符號和第一個操作數(shù)的符號保持一致。
NaN + NaN ?
NaN - NaN ?
NaN * NaN ?
NaN / NaN
NaN % NaN
0/0
// ?以上運算結(jié)果均為NaN
1) "+"運算符
總的來說,加號的轉(zhuǎn)換規(guī)則優(yōu)先考慮字符串鏈接。如果兩個操作數(shù)不是類字符串的,那么將進(jìn)行算術(shù)加法運算。
加法操作符的完整行為表現(xiàn)為:
如果其中一個操作數(shù)是對象,則對象會遵循對象到原始值得轉(zhuǎn)換規(guī)則轉(zhuǎn)換為原始類值:日期對象通過toString()方法執(zhí)行轉(zhuǎn)換,其他對象則通過valueOf()方法執(zhí)行轉(zhuǎn)換。由于對數(shù)對象不具備可用的valueOf()方法,因此會通過toString()方法來執(zhí)行轉(zhuǎn)換。
進(jìn)行對象到原始值的轉(zhuǎn)換后,如果其中一個操作數(shù)是字符串的話,另一個操作數(shù)也會轉(zhuǎn)換為字符串,然后進(jìn)行字符串連接。
否則,兩個操作數(shù)都將轉(zhuǎn)換為數(shù)字(或NaN),然后進(jìn)行加法運算。
舉個例子:
1 + 2? // 3:加法
"1" + "2"? //"12":字符串連接
"1" + 2? //"12":數(shù)字轉(zhuǎn)換為字符串后進(jìn)行字符串連接
1 + {}? // "1[object Object]":對象轉(zhuǎn)換為字符串后進(jìn)行字符串連接
true + true ?// 2:布爾值轉(zhuǎn)換為數(shù)字相加
2 + null ?// ?2:null轉(zhuǎn)換為0后做加法
2 + undefined // NaN:undefined轉(zhuǎn)換為NaN后相加
2) 一元算術(shù)運算符
一元運算符作用于一個單獨的操作數(shù),并產(chǎn)生一個新值。必要時,他們會將操作數(shù)轉(zhuǎn)換為數(shù)字。所以表達(dá)式++x不總和x = x + 1完全一樣。"++"運算符從不進(jìn)行字符串連接操作,它總是會將操作數(shù)轉(zhuǎn)換為數(shù)字并增1。如果x是字符串"1",++x就是先將字符串轉(zhuǎn)換為數(shù)字同時增1,即2。而x + 1的結(jié)果是字符串"11"。
第五章 語句
嚴(yán)格模式與非嚴(yán)格模式的區(qū)別(前三條很重要):
1、在嚴(yán)格模式下禁止使用with語句。
2、在嚴(yán)格模式中,所有變量都要先聲明。如果給一個未聲明的變量、函數(shù)、函數(shù)參數(shù)、catch從句參數(shù)或全局對象的屬性賦值,將拋出錯誤。(非嚴(yán)格模式中,隱式聲明的全局變量的方法是給全局對象新添加一個新屬性)。
3、在嚴(yán)格模式中,調(diào)用的函數(shù)中的一個this值是undefined。(非嚴(yán)格模式中,調(diào)用的函數(shù)中的this總是全局對象,比如window)。
4、嚴(yán)格模式中,當(dāng)通過call()或apply()來調(diào)用函數(shù)時,其中的this值就是通過call()或apply()傳入的第一個參數(shù)。(非嚴(yán)格模式中,null和undefined值被全局對象和轉(zhuǎn)換為對象的非對象值所代替)。
5、嚴(yán)格模式中,給只讀屬性賦值和給不可擴(kuò)展的對象創(chuàng)建新成員會拋出類型錯誤(非嚴(yán)格模式下,只是操作失敗,并不報錯)。
6、嚴(yán)格模式中,函數(shù)里的arguments對象擁有傳入函數(shù)值的靜態(tài)副本(?不是很理解)。非嚴(yán)格模式下,arguments里的數(shù)組元素和函數(shù)參數(shù)都是指向同一個值得引用。
7、嚴(yán)格模式下,當(dāng)delete運算符后跟隨非法的標(biāo)識符(如變量、函數(shù)等)時,將拋出語法錯誤。非嚴(yán)格模式中,這種delete表達(dá)式什么也不做,并返回false。
8、嚴(yán)格模式中,在一個對象直接量中定義兩個或多個同名屬性將產(chǎn)生一個語法錯誤。(非嚴(yán)格模式不會報錯)。同時在es6中,會進(jìn)行覆蓋,后聲明的會覆蓋先前的。
9、嚴(yán)格模式中,函數(shù)聲明中存在兩個或多個同名的參數(shù)將產(chǎn)生一個語法錯誤(非嚴(yán)格模式不報錯)。
10、嚴(yán)格模式不允許使用八進(jìn)制整數(shù)直接量。
第六章 對象
創(chuàng)建對象有三種方式,包括對象字面量、new和Object.create().
Object.create()接受兩個參數(shù)。第一個參數(shù)是這個對象的原型。第二個可選參數(shù)用以對對象的屬性進(jìn)行進(jìn)一步描述。
可以通過傳入?yún)?shù)null來創(chuàng)建一個沒有原型的新對象,但是通過這種方法創(chuàng)建的對象不會繼承任何東西,甚至不包括基礎(chǔ)方法。比如toString()。
如果想創(chuàng)建一個普通的空對象(比如{}),需要傳入Object.prototype:
var obj = Object.create(Object.prototype); // 和new Object()一樣
屬性的查詢和設(shè)置
可以通過點(.)或方括號([])運算符來獲取對象屬性的值。對于點(.)來說,右側(cè)必須是一個以屬性名稱命名的簡單標(biāo)識符。對于方括號來說([]),方括號內(nèi)必須是一個計算結(jié)果為字符串的表達(dá)式。更嚴(yán)格地講,表達(dá)式必須返回字符串或返回一個可以轉(zhuǎn)換為字符串的值。需要注意的是,如果屬性的名字是數(shù)字的話,使用點運算符會報錯,必須使用方括號進(jìn)行查詢。
方括號運算符的優(yōu)點在于方括號使用字符串值(字符串值是動態(tài)的,可以在運行時更改)。而標(biāo)識符是靜態(tài)的,必須寫死在程序中。
屬性訪問錯誤
查詢一個不存在的屬性并不會報錯,訪問不存在的表達(dá)式會返回undefined。但是,如果對象不存在,那么試圖查詢不存在的對象的屬性就會報錯。程序中可以用短路運算&&防止此類事情發(fā)生。obj && obj.attr
當(dāng)然,給null和undefined設(shè)置屬性也會報類型錯誤。在一下場景下給對象o設(shè)置屬性p會失敗:
o中的屬性p是只讀的:不能給只讀屬性重新賦值。
o中的屬性p是繼承屬性,并且是只讀的:不能通過同名自有屬性覆蓋只讀的繼承屬性。
o中不存在自有屬性p:o沒有使用setter方法繼承屬性p,并且o的可擴(kuò)展行是false。如果o中不存在p,而且沒有setter方法可供調(diào)用,則p一定會添加至o中。但如果o不是可擴(kuò)展的,那么在o中不能定義新屬性。(好拗口)
刪除屬性
delete運算符可以刪除對象的屬性。操作數(shù)應(yīng)該是一個屬性訪問表達(dá)式。delete運算符只能刪除自有屬性,不能刪除繼承屬性。當(dāng)delete表達(dá)式刪除成功或沒有任何副作用(比如刪除不存在的屬性)時,會返回true。
var o = {};
delete o.x; //刪除不存在的屬性 ?返回true
delete o.toString; //刪除繼承的屬性,但無法刪除 依舊返回true
delete 1; // 運算符后不是屬性訪問表達(dá)式,沒有實際意義,依舊返回true
delete不能刪除那些可配置性為false的屬性。某些內(nèi)置對象的屬性是不可配置的,比如通過變量聲明和函數(shù)聲明創(chuàng)建的全局對象的屬性。
檢測屬性
首先是in運算符。in運算符的左側(cè)是屬性名(需是字符串),右側(cè)是對象。如果對象的自有屬性或繼承屬性中包含則返回true。(敲重點,對象的自有屬性或繼承屬性)
還有hasOwnProperty()方法。該方法用來檢測給定的名字是否是對象的自有屬性。繼承屬性會返回false。(敲重點,自有屬性返回true,其他的包括繼承的返回false)
propertyIsEnumerable()是hasOwnProperty()的增強版,只有檢測到是自有屬性并且這個屬性的可枚舉性為true時才返回true。一般來說,JS代碼創(chuàng)建的都是可枚舉的。
可以使用!==來判斷某個屬性是否為undefined。但是in可以區(qū)分不存在的屬性和存在值為undefined的屬性。也就是說,某個屬性顯示賦值為undefined時,in返回true,而不全等則返回false。
var o = {x:1};
"x" in o; // true
"toString" in o // 繼承屬性,返回true
o.hasOwnProperty("x"); // 自身屬性,返回true
o.hasOwnProperty("toString"); // 繼承屬性,返回false
o.propertyIsEnumerable("x"); //可枚舉的自身屬性,返回true
枚舉屬性
for/in循環(huán)可以遍歷對象中所有可枚舉的屬性,包括繼承的。還有兩個ES5定義的枚舉屬性名稱的函數(shù)。第一個是Object.keys(),它返回一個數(shù)組,數(shù)組由對象可枚舉的自有屬性的名稱組成。第二是Object.getOwnPropertyNames(),返回對象的所有自有屬性的名稱,包括不可枚舉的!也就是說兩者都是返回自身屬性,只不過前者無法返回不可枚舉的,后者可以返回不可枚舉的。
var o = {x:1,y:2};
Object.keys(a); //["x","y"],返回自身可枚舉屬性名稱的數(shù)組
Object.getOwnPropertyNames(a); //["x", "y"]
//本例沒有不可枚舉屬性,所以兩者返回相同的數(shù)組
對象的三個屬性
1)原型屬性
對象的原型屬性是用來繼承屬性的。原型屬性是在實例對象創(chuàng)建之初就設(shè)置好的。通過對象直接量的對象使用Object.prototype作為原型。通過new創(chuàng)建的對象使用構(gòu)造函數(shù)的prototype屬性作為原型。通過Object.create()創(chuàng)建的對象使用第一個參數(shù)作為原型。
如若檢測一個對象是否是另一個對象的原型(或處于原型鏈中),請使用isPrototypeOf()方法。
var p = {x:1};
var o = Object.create(p); //使用p原型創(chuàng)建對象
p.isPrototypeOf(o); //true
Object.prototype.isPrototypeOf(o); //true 均為繼承
第七章 數(shù)組
如果省略數(shù)組直接量中的某個值,省略的元素的值為undefined。
var count = [1,,3]; // count[1]的值為undefined
var undefs = [,,]; //undefs.length為2,數(shù)組直接量的語法允許有可選的結(jié)尾逗號,所以[,,]只有2個元素,而不是3個。
數(shù)組的元素的讀和寫
使用[]操作符來訪問數(shù)組。方括號中是一個返回非負(fù)整數(shù)值得任意表達(dá)式。數(shù)組是對象的特殊形式,使用[]訪問數(shù)組元素就像用方括號訪問對象屬性一樣。數(shù)組的特別之處在于,當(dāng)使用小于2^32的非負(fù)整數(shù)作為屬性名時數(shù)組會自動維護(hù)其length屬性值。舉個例子:
var a = [];
a[1] = 1;
a[2] = 2;
a.length? //? => 3
//也就是說,給數(shù)組a賦值小于2^32的非負(fù)整數(shù)的屬性名時,數(shù)組會自動擴(kuò)展為其length屬性值。但是,屬性值超過2^32的正整數(shù)或者負(fù)數(shù)時,就不會維護(hù)為length屬性值了。接著看下面的例子
var b = [];
b[Math.pow(2,32)] = 3;
b;? //? ? => [4294967296: 3];
b[-1] = 4;
b;? //? ? => [4294967296: 3, -1: 4]
所有的索引都是屬性名,但只有在0~2^32 - 2之間的整數(shù)屬性名才是索引。
可以使用負(fù)數(shù)或者非整數(shù)來索引數(shù)組。這種情況下,數(shù)值會轉(zhuǎn)換為字符串,字符串作為屬性名來用。因為此情況為非負(fù)整數(shù),所以只能當(dāng)常規(guī)的對象屬性,而非數(shù)組的索引。舉個例子:
a[-1.23] = true; ?// 創(chuàng)建名為‘-1.23’的屬性
a["1000"] = 0; ?//數(shù)組的第1001個元素
a[1.000] ?//等同于a[1]
數(shù)組索引僅僅是對象屬性名的一種特殊類型,意味著數(shù)組沒有越界錯誤的概念。也就是說,當(dāng)試圖查詢?nèi)魏螌ο笾胁淮嬖诘膶傩詴r,不會報錯,僅僅得到undefined值。
稀疏數(shù)組
稀疏數(shù)組就是包含從0開始的不連續(xù)索引的數(shù)組。意味著稀疏數(shù)組length屬性值大于元素的個數(shù)。最簡單粗暴的創(chuàng)建稀疏數(shù)組的方式:var a = new Array(10); 0個元素,長度為10。
足夠稀疏的數(shù)組通常在實現(xiàn)上比稠密的數(shù)組更慢、內(nèi)存利用率更高,在這樣的數(shù)組中查找元素的事件與常規(guī)對象屬性的查找時間一樣長。在數(shù)組直接量中省略值時不會創(chuàng)建稀疏數(shù)組。因為省略的元素在數(shù)組中是存在的,值為undefined。這和元素不存在還是有區(qū)別的,請看下例:
var a1 = [,,,];? //? =>[undefined,undefined,undefined]
var a2 = new Array(3); ? // ?=>數(shù)組根本沒有元素
0 in a1 ? ?// ? =>true;因為a1在索引0處有元素,為undefined
0 in a2 ? // ? ?=>false; ?a2在索引0處沒有元素
數(shù)組長度
如果為一個數(shù)組元素賦值,它的索引i大于或等于現(xiàn)有數(shù)組的長度時,length屬性的值將設(shè)置為 ? i + 1。相對的,設(shè)置length屬性為一個小于當(dāng)前長度的非負(fù)整數(shù)n時,當(dāng)前數(shù)組中那些索引值大于等于n的元素將被刪除:
var a = [1,2,3,4,5];?
a.length = 0; ? //刪除所有元素,a為[]
a.length = 5; ? //等同于new Array(5)
刪除數(shù)組元素與為其賦undefined值得類似的。對一個數(shù)組元素使用delete不會修改數(shù)組的length屬性,也不會將元素從高索引出移下來填充已刪除屬性的空白。如果刪除元素,就會變成稀疏數(shù)組。
數(shù)組方法
1)join()----------不會改變原數(shù)組
Array.join()將數(shù)組中所有元素都轉(zhuǎn)化為字符串并連接在一起,返回最后生成的字符串。可以指定可選的字符串在生成的字符串中分隔數(shù)組元素。默認(rèn)使用逗號。Array.join()是String.split()方法的逆向操作,后者根據(jù)指定正則來分割字符串為一個數(shù)組。
var a = [1,2,3];
a.join();? //? ? =>"1,2,3"
a.join(" ");? //? ? =>"1 2 3"
var b = new Array(10);
b.join('-')? ? //? ? => "---------"
2)reverse()---------會改變原數(shù)組
Array.reverse()方法將數(shù)組中的元素顛倒順序,返回逆序的數(shù)組。需要注意的是,該方法是在原先的數(shù)組中重新排列。
var a = [1,2,3];
a.reverse(); ? // ? => [3,2,1]
a;// ? => [3,2,1]
3)? sort() ---------會改變原數(shù)組
該方法將數(shù)組中的元素排序并返回排序后的數(shù)組。當(dāng)不帶參數(shù)調(diào)用時,數(shù)組元素以字母表順序排序(有必要時臨時轉(zhuǎn)化為字符串進(jìn)行比較)。如果數(shù)組包含undefined元素,會被排到數(shù)組的尾部。
該方法可以傳一個可選的參數(shù),參數(shù)必須是函數(shù)。也就是所謂的比較函數(shù)比較函數(shù)應(yīng)該具備兩個參數(shù)a和b,返回值如下:
若a小于b,在排序后的數(shù)組中a應(yīng)該出現(xiàn)在b之前,則返回一個小于0的值。
若a等于b,則返回0。
若a大于b,則返回一個大于0的值。
下面是一個打算數(shù)字?jǐn)?shù)組的順序的方法:
var sortArray = array.sort(function(){
? ? return Math.random() - 0.5;
})
4) ?concat() ?---------不會改變原數(shù)組
該方法創(chuàng)建并返回一個新數(shù)組,元素包括調(diào)用concat()的原始數(shù)組的元素和該方法的每個參數(shù)。concat()不會修改調(diào)用的方法。而且concat()不會遞歸扁平化數(shù)組的數(shù)組。如果不傳參數(shù),則返回調(diào)用該方法的數(shù)組,也就相當(dāng)于對數(shù)組進(jìn)行了一次復(fù)制(淺復(fù)制)。
var a = [1,2,3];
a.concat(4,5);
a.concat([4,5]); ?// ?=>均返回[1,2,3,4,5]
5) slice() ---------不會改變原數(shù)組,該單詞含義為切片,劃分
該方法返回指定數(shù)組的一個片段或者子數(shù)組。兩個參數(shù)分別指定了片段的開始和結(jié)束的位置。可以簡單的理解為左閉右開([start,end))。如果只指定一個參數(shù),返回的數(shù)組包含從開始位置到結(jié)尾的所有元素。如果單參數(shù)為負(fù)數(shù),則開始位置從最后一個元素開始。
var a = [1,2,3,4,5];
a.slice(0,3); ? // ?=>索引從[0,3),不包含第4個元素,返回[1,2,3]
a.slice(3); ? // ?=>從a[3]開始到最后一個元素,返回[4,5]
6) splice() -------------會改變原數(shù)組,該單詞含義為粘接
該方法能夠從數(shù)組中刪除元素、插入元素到數(shù)組中或者同時完成刪除和插入。使用該方法后,數(shù)組元素會根據(jù)需要增加或減小索引值,因此數(shù)組的其他部分仍然是連續(xù)的。第一個參數(shù)指定了插入、刪除的起始位置。第二個參數(shù)指定應(yīng)該從數(shù)組中刪除元素的個數(shù)。若省略第二元素,從起始點到結(jié)尾所有元素都會被刪除。splice()返回一個有刪除元素組成的數(shù)組,或者如果沒刪除元素就返回空數(shù)組。splice()的前兩個參數(shù)指定了需要刪除的數(shù)組元素。后面的任意參數(shù)指定了需要插入到數(shù)組中的元素,從第一個參數(shù)指定的位置開始插入。也就是說,第一個參數(shù)是刪除或插入的起始位置。舉個例子:
var a = [1,2,3,4,5,6,7,8];
a.splice(4); ? ?// 指定一個參數(shù),意味著從a[4]開始到末尾都會被刪除,此時會返回 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//[5,6,7,8],然后原數(shù)組a變?yōu)閇1,2,3,4]?
a.splice(1,2); ? //注意此時原數(shù)組為[1,2,3,4],兩個參數(shù)指定了從a[1]開始刪除2個元素,返 ? ? ? ? ? ? ? ? ? ? ? ? ?//回[2,3],同時原數(shù)組變?yōu)閇1,4]
a.splice(1,0,[1,2],3); ? //此時方法多于2個參數(shù),意味著會進(jìn)行刪除和插入操作。從a[1]開始刪除0個元素,同時在指定位置左側(cè)插入'[1,2],3',由于刪除了0個元素,所以會返回[],同時a變?yōu)閇1,[1,2],3,4]
項目中遇到了對列表上移和下移的需求,剛好用到了splice,大致代碼如下:
//? 對selectItem數(shù)組上移操作
if(!index)return;//如果是第一項就返回,第一項當(dāng)然不允許上移了
this.selectItem.splice(index-1,0,(this.selectItem[index]));
//既然要上移,那我們肯定要插入到前一項的左側(cè)了,所以第一個參數(shù)是index-1,然后第三參數(shù)將當(dāng)前項插入到數(shù)組中,注意此時是有2個當(dāng)前項的,假設(shè)我們是對數(shù)組的第二項進(jìn)行操作的,那么現(xiàn)在返回的數(shù)組第一項和第三項都是進(jìn)行上移的那一項,所以我們必須刪除重復(fù)的。
this.selectItem.splice(index+1,1);
//我們來進(jìn)行刪除操作,注意現(xiàn)在新數(shù)組的第一項和第三項都是我們移動的那個值,而當(dāng)前index為1,所以我們需要操作index+2,也就是第三項,將其刪除。//下移
if(index ===this.selectItem.length -1)return;//如果為最后一項 ,不允許下移
this.selectItem.splice(index+2,0,(this.selectItem[index]));
//既然要下移,那么我們就要將當(dāng)前數(shù)據(jù)插入到下下位的左側(cè)了,如果是index+1,那還是在原來的地方多了一個重復(fù)的數(shù)據(jù),等于沒移動!
this.selectItem.splice(index,1);
// 這個好理解,直接將原來的值刪除即可。
7) push()和pop() ------------會修改原數(shù)組
push()在數(shù)組尾部添加一個或多個元素,返回數(shù)組新的長度。pop()刪除數(shù)組的最后一個元素,同時返回刪除的那個值。來總結(jié)一下,兩個方法都是在數(shù)組尾部操作,而且push支持多個參數(shù),pop不傳參數(shù),就算傳了參數(shù)也會忽略參數(shù),而且只能刪除最后一個元素并返回這個值。
8) unshift()和shift() ----------會修改原數(shù)組
這兩個方法跟上面的方法十分類似,只不過是修改的數(shù)組的頭部而非尾部。unshift()對應(yīng)push()方法,在數(shù)組頭部添加一個或多個元素,并將已存在的元素移動到更高索引的位置來獲得足夠的空間,最后返回數(shù)組新的長度。shift()對應(yīng)pop()方法,刪除第一個元素并返回,將隨后的元素下移一個位置填補空缺。
值得注意的一個地方,unshift()使用多個參數(shù)調(diào)用時,參數(shù)是一次性插入的,而不是一個個的插入。這意味著最終的數(shù)組中插入元素的順序和在參數(shù)中的順序保持一致,如果每次插入一個參數(shù),則恰好反過來。來個例子:
var a= [3];
a.unshift(1,2); ? // ?返回數(shù)組長度3,此時a為[1,2,3];
a.unshift(1); // 2
a.unshift(2); ?// 3 ?此時a為[2,1,3]
這兩對好基友可以讓數(shù)組實現(xiàn)類似隊列的效果(FIFO):
push()在數(shù)組尾部將元素添加,shift()在數(shù)組頭部將元素刪除;<-------
unshift()在數(shù)組頭部將元素添加,pop()在數(shù)組尾部將元素刪除;------->
9) toString()和toLocaleString()
數(shù)組同樣也擁有toString()方法。該方法將每個元素轉(zhuǎn)化為字符串,有必要的話還會調(diào)用元素的toString()方法。并且輸出用逗號分隔的字符串列表。要注意的是,輸出不包括方括號或者其他任何形式的包裹數(shù)組值得分隔符。結(jié)果與不使用任何參數(shù)調(diào)用join()方法返回的字符串相同。
[1,2,3].toString() ? ? ? ? ? ?// ?'1,2,3'
["a","b","c"].toString() ? ?// ?'a,b,c'
toLocaleString()是toString()方法本地化版本。
ES5中的數(shù)組方法
大多數(shù)方法的第一個參數(shù)接收一個函數(shù),并且對數(shù)組的每個元素或一些元素調(diào)用該函數(shù)。也就是說,大多是方法是對數(shù)組進(jìn)行遍歷的。如果是稀疏數(shù)組,對不存在的元素不調(diào)用傳遞的參數(shù)。大部分情況下,調(diào)用的函數(shù)提供三個參數(shù):數(shù)組元素、元素的索引和數(shù)組本身(item,index,array)。第二個參數(shù)是可選的,如果有的話,則調(diào)用的函數(shù)被看做是第二個參數(shù)的方法。也就是說,在調(diào)用函數(shù)時傳遞進(jìn)去的第二個參數(shù)作為它的this關(guān)鍵字的值來使用。
ES5的數(shù)組方法都不會修改原數(shù)組。
1)forEach()
這個已經(jīng)用的很多了,說一個注意點。forEach()無法提前終止遍歷。如果要提前終止,必須把方法放在一個try塊中,并能拋出一個異常。
2) ?map()
該方法將調(diào)用的數(shù)組的每個元素傳遞給指定函數(shù),并返回一個新的數(shù)組,包含函數(shù)的返回值。
所以map()的函數(shù)參數(shù)應(yīng)該有返回值。如果是稀疏數(shù)組,返回的也是相同方式的稀疏數(shù)組:相同的長度,相同的缺失元素。
經(jīng)實踐,如果在函數(shù)中進(jìn)行break,會報錯。如果對滿足某個條件的元素return,則該元素對應(yīng)的位置為undefined,如果return其他值,則該位置為對應(yīng)值,包括return false。
var a = [1,2,3];
a.map(function(x){
? ? ? ? if (x === 2)? return;
? ? ? ? return x + x;
});? ? //? [2, undefined, 6]
a.map(function(x){
? ? ? ? if (x === 2) return false;
? ? ? ? return x + x;
});? //? [2, false, 6]
3) ?filter()
該方法返回的數(shù)組元素是調(diào)用的數(shù)組的一個子集。如果返回值為true或能轉(zhuǎn)化為true的值,那么傳遞給判定函數(shù)的元素就是這個子集的成員。方法會跳過稀疏數(shù)組中缺少的元素,它的返回數(shù)組總是稠密的。
4)every()和some()
兩個方法是數(shù)組的邏輯判定:它們對數(shù)組元素應(yīng)用指定的函數(shù)進(jìn)行判定,返回true或false。
如果數(shù)組中的所有元素調(diào)用判定函數(shù)全部都返回true,every()方法才返回true,其他一律返回false。如果數(shù)組中至少有一個元素調(diào)用判定函數(shù)返回true,它就返回true。只有所有的元素調(diào)用判定函數(shù)返回false,它才返回false。
var a = [1,2,3,4,5];
a.every(function(x) {return x % 2 === 0;})? // false? 不是所有數(shù)都是偶數(shù)
a.some(function(x) {return x % 2 === 0;}) ? //true ? 含有偶數(shù)
5) reduce()和reduceRight()
方法使用指定的函數(shù)將數(shù)組元素進(jìn)行組合,生成單個值。
reduce()需要兩個參數(shù),第一個是執(zhí)行化簡操作的函數(shù)。化簡函數(shù)的任務(wù)就是用某種方法把兩個值合成為一個值,并返回。第一次調(diào)用函數(shù)時,第一個參數(shù)是一個初始值,就是傳遞給reduce()的第二個參數(shù)。下一次調(diào)用中,這個值就是上次化簡函數(shù)的返回值。舉個例子:
var a = [1,2,3,4,5];
var sum = a.reduce(function(x,y){return x+y},0);
在這個例子中,第一次調(diào)用化簡函數(shù)時的參數(shù)是0(化簡函數(shù)的第二個參數(shù),即初始值)和1(數(shù)組的第一項),將兩個相加返回1,再次調(diào)用的時候參數(shù)為返回值1和數(shù)組的第二項2,然后返回3。依次相加得到15,reduce方法返回這個值。
當(dāng)不指定初始值調(diào)用reduce()時,它將使用數(shù)組的第一個元素作為初始值。這意味著第一次調(diào)用化簡函數(shù)的時候就使用第一個和第二個數(shù)組元素作為第一和第二個參數(shù)。但是在空數(shù)組上,不帶初始值參數(shù)調(diào)用reduce()將導(dǎo)致類型錯誤異常。如果調(diào)用它的時候只有一個值(數(shù)組只有一個元素并且沒有指定初始值,或者有一個空數(shù)組并且指定了一個初始值),reduce()只是簡單地返回那個值而不會調(diào)用化簡函數(shù)。
reduceRight()與reduce()不同的是,它按照數(shù)組索引從高到低來處理數(shù)組。
5) indexOf()與lastIndexOf()
方法搜索整個數(shù)組中具有給定值得元素,返回找到的第一個元素的索引或沒有找到就返回-1。
indexOf()從頭至尾搜索,lastIndexOf()相反。
兩個方法不接受一個函數(shù)作為參數(shù)。他們的參數(shù)是這樣的:第一個參數(shù)是需要搜索的值,第二個參數(shù)是可選的,指定數(shù)組中的一個索引,從索引出開始搜索。第二個參數(shù)也可以是負(fù)數(shù),代表相對數(shù)組末尾的偏移量。