在使用js編程的時候,常常會用到集合對象,集合對象其實是一種泛型,在js中沒有明確的規定其內元素的類型,但在強類型語言譬如Java中泛型強制要求指定類型。
ES6引入了iterable類型,Array,Map,Set都屬於iterable類型,它們可以使用for...of循環來遍歷,都內置forEach方法。
數組
遍歷
普通遍歷
最簡單的一種,也是使用頻率最高的一種。
let arr = ['a', 'b', 'c', 'd', 'e'] for (let i = 0; i < arr.length; i++) { console.log(i, ' => ', arr[i]) }
優化: 緩存數組長度:
let arr = ['a', 'b', 'c', 'd', 'e'] for (let i = 0, len = arr.length; i < len; i++) { console.log(i, ' => ', arr[i]) }
使用臨時變量,將長度緩存起來,避免重復獲取數組長度,當數組較大時優化效果才會比較明顯。
for-in
這個循環很多人愛用,但實際上,經分析測試,在眾多的循環遍歷方式中它的效率是最低的。
let arr = ['a', 'b', 'c', 'd', 'e'] for (let i in arr) { console.log(i, ' => ', arr[i]) }
for-of
這種方式是es6里面用到的,性能要好於forin,但仍然比不上普通for循環。
let arr = ['a', 'b', 'c', 'd', 'e'] let index = 0 for (let item of arr) { console.log(index++, ' => ', item) }
forEach
數組自帶的foreach循環,使用頻率較高,實際上性能比普通for循環弱。
let arr = ['a', 'b', 'c', 'd', 'e'] arr.forEach((v, k) => { console.log(k, ' => ', v) })
forEach接受第三個參數,指向原數組,沒有返回值,對其進行操作會改變原數組對象
let ary = [12, 23, 24, 42, 1] let res = ary.forEach((item, index, input) => { input[index] = item * 10 }) console.log(res) //-->undefined console.log(ary) //-->會對原來的數組產生改變
如果版本低的瀏覽器不兼容(IE8-),可以自定義方法實現:
/**
* forEach遍歷數組
* @param callback [function] 回調函數;
* @param context [object] 上下文;
*/
Array.prototype.myForEach = function (callback,context) { context = context || window; if('forEach' in Array.prototype) { this.forEach(callback,context) return } // IE6-8下自己編寫回調函數執行的邏輯 for(let i = 0,len = this.length; i < len; i++) { callback && callback.call(context, this[i], i, this) } } let arr = [12, 23, 24, 42, 1] arr.myForEach((v, k) => { console.log(k, ' => ', v) })
map
map會返回一個全新的數組,同樣接受第三個參數,如果對其進行操作會改變原數組。
let ary = [12, 23, 24, 42, 1] let res = ary.map((item, index, input) => { return item * 10 }) console.log(res) //-->[120,230,240,420,10] console.log(ary) //-->[12,23,24,42,1]
如果版本低的瀏覽器不兼容(IE8-),可以自定義方法實現:
/**
* map遍歷數組
* @param callback [function] 回調函數;
* @param context [object] 上下文;
*/
Array.prototype.myMap = function myMap(callback,context){ context = context || window if('map' in Array.prototype) { return this.map(callback, context) } //IE6-8下自己編寫回調函數執行的邏輯 let newAry = [] for(var i = 0,len = this.length; i < len; i++) { if(typeof callback === 'function') { var val = callback.call(context, this[i], i, this) newAry[newAry.length] = val } } return newAry } arr.myMap((v, k) => { console.log(k, ' => ', v) })
過濾
filter
對數組中的每個元素都執行一次指定的函數(callback),並且創建一個新的數組,該數組元素是所有回調函數執行時返回值為 true 的原數組元素。它只對數組中的非空元素執行指定的函數,沒有賦值或者已經刪除的元素將被忽略,同時,新創建的數組也不會包含這些元素。
let arr = [12, 5, 8, 130, 44] let ret = arr.filter((el, index, array) => { return el > 10 }) console.log(ret) // [12, 130, 44]
map
map也可以作為過濾器使用,不過返回的是對原數組每項元素進行操作變換后的數組,而不是每項元素返回為true的元素集合。
let strings = ["hello", "Array", "WORLD"]
function makeUpperCase(v) { return v.toUpperCase() } let uppers = strings.map(makeUpperCase) console.log(uppers) // ["HELLO", "ARRAY", "WORLD"]
some
對數組中的每個元素都執行一次指定的函數(callback),直到此函數返回 true,如果發現這個元素,some 將返回 true,如果回調函數對每個元素執行后都返回 false ,some 將返回 false。它只對數組中的非空元素執行指定的函數,沒有賦值或者已經刪除的元素將被忽略。
// 檢查是否有數組元素大於等於10:
function isBigEnough(element, index, array) { return (element >= 10) } let passed1 = [2, 5, 8, 1, 4].some(isBigEnough) // passed1 is false let passed2 = [12, 5, 8, 1, 4].some(isBigEnough) // passed2 is true
every
對數組中的每個元素都執行一次指定的函數(callback),直到此函數返回 false,如果發現這個元素,every 將返回 false,如果回調函數對每個元素執行后都返回 true ,every 將返回 true。它只對數組中的非空元素執行指定的函數,沒有賦值或者已經刪除的元素將被忽略。
// 測試是否所有數組元素都大於等於10:
function isBigEnough(element, index, array) { return (element >= 10) } let passed1 = [12, 5, 8, 1, 4].every(isBigEnough) // passed1 is false let passed2 = [12, 15, 18, 11, 14].every(isBigEnough) // passed2 is true
排序
let arr = ['a', 1, 'b', 3, 'c', 2, 'd', 'e'] console.log(arr) // ["a", 1, "b", 3, "c", 2, "d", "e"] console.log(arr.reverse()) // 反轉元素(改變原數組) // ["e", "d", 2, "c", 3, "b", 1, "a"] console.log(arr.sort()) // 對數組元素排序(改變原數組) // [1, 2, 3, "a", "b", "c", "d", "e"] console.log(arr) // [1, 2, 3, "a", "b", "c", "d", "e"]
sort自定義排序
let arr = [1, 100, 52, 6, 88, 99] let arr1 = arr.sort((a, b) => a-b) // 從小到大排序 console.log(arr1) // [1, 6, 52, 88, 99, 100] let arr2 = arr.sort((a, b) => b-a) // 從大到小排序 console.log(arr2) // [100, 99, 88, 52, 6, 1] console.log(arr) // 原數組也發生改變
搜索
let arr = [12, 5, 4, 8, 1, 4] arr.indexOf(4) // 2,從前往后搜索,返回第一次搜索到的數組下標,搜索不到返回-1 arr.lastIndexOf(4) // 5,從后往前搜索,返回第一次搜索到的數組下標,搜索不到返回-1 arr.indexOf(0) // -1
增刪、清空操作
添加元素
let arr = ['a', 'b', 'c', 'd', 'e'] arr.push(10, 11) // 模仿棧進行操作,往數組末尾添加一個或多個元素(改變原數組) arr.unshift(0, 1) // 模仿隊列進行操作,往數組前端添加一個或多個元素(改變原數組) console.log(arr) // [0, 1, "a", "b", 'c', "d", "e", 10, 11]
刪除元素
arr.pop() // 移除最后一個元素並返回該元素值(改變原數組)
arr.shift() // 移除最前一個元素並返回該元素值,數組中元素自動前移(改變原數組)
console.log(arr) // ["b", "c", "d"]
清空數組
將數組的length設置為0即可
let arr = ['a', 1, 'b', 3, 'c', 2, 'd', 'e'] arr.length = 0
length詳解:
- 因為數組的索引總是由0開始,所以一個數組的上下限分別是:0和length-1;
- 當length屬性被設置得更大時,整個數組的狀態事實上不會發生變化,僅僅是length屬性變大;
- 當length屬性被設置得比原來小時,則原先數組中索引大於或等於length的元素的值全部被丟失。
splice
既可以刪除也可以添加元素
let arr = ['a', 'b', 'c', 'd', 'e'] arr.splice(2, 1, 1,2,3) console.log(arr) // ["a", "b", 1, 2, 3, "d", "e"]
splice(start, len, elems) : 刪除並添加元素(改變原數組)
- start: 起始位置
- len: 刪除元素的長度
- elems: 添加的元素隊列
- 幾種形式:
- splice(start, 0, elems) : 從start位置添加元素
- splice(start, len) : 從start位置刪除len個元素
截取、合並與拷貝
let arr = ['a', 'b', 'c', 'd', 'e'] let arr1 = arr.slice(1, 2) // 以數組的形式返回數組的一部分,注意不包括 end 對應的元素,如果省略 end 將復制 start 之后的所有元素(返回新數組) let arr2 = arr.concat([1,2,3]); // 將多個數組(也可以是字符串,或者是數組和字符串的混合)連接為一個數組(返回新數組) console.log(arr) // ["a", "b", "c", "d", "e"] console.log(arr1) // ["b"] console.log(arr2) // ["a", "b", "c", "d", "e", 1, 2, 3]
其實
slice
和concat
也可以作為數組的拷貝方法:
arr.slice(0) // 返回數組的拷貝數組,注意是一個新的數組,不是指向
arr.concat() // 返回數組的拷貝數組,注意是一個新的數組,不是指向
Map
Map是一組鍵值對的結構,具有極快的查找速度。
創建
方法一: 創建的時候初始化
let mapObj = new Map([
['a', 1], ['b', 2], ['c', 3] ]) console.log(mapObj.size) // 3
方法二: 創建空Map,之后添加元素
let mapObj = new Map()
mapObj.set('a', 1) mapObj.set('b', 2) mapObj.set('c', 3) console.log(mapObj.size) // 3
注意: Map對象的長度不是length,而是size
基礎操作
Map對象的創建、添加元素、刪除元素...
mapObj.set('a', 1) // 添加元素
mapObj.delete('d') // 刪除指定元素 mapObj.has('a') // true mapObj.get('a') // 1
遍歷
使用上面創建的Map進行操作
forEach
同數組的forEach遍歷,三個參數分別代表: value、key、map本身
mapObj.forEach((e, index, self) => {
console.log(index, ' => ', e)
})
打印出:
a => 1
b => 2
c => 3
for-of
for (const e of mapObj) {
console.log(e)
}
打印出:
["a", 1]
["b", 2]
["c", 3]
注意: for-of遍歷出來的是一個數組,其中e[0]為key,e[1]為value
Set
Set和Map類似,但set只存儲key,且key不重復。
創建
方法一: 創建的時候初始化
let setObj = new Set([1, 2, 3]) console.log(setObj.size)
方法二: 創建空Map,之后添加元素
let setObj = new Set()
setObj.add(1)
setObj.add(2) setObj.add(3) console.log(setObj.size)
注意: Map對象的長度不是length,而是size
基礎操作
let s = new Set([1, 2, 3]) s.add(3) // 由於key重復,添加不進 s.delete(3) // 刪除指定key console.log(s) // 1 2
遍歷
使用上面創建的Set進行操作
forEach
Set與Array類似,但Set沒有索引,因此回調函數的前兩個參數都是元素本身
s1.forEach(function (element, sameElement, set) {
console.log(element) // element === sameElement }) // 打印 1 2 3
for-of
for (const item of s1) {
console.log(item)
}
// 打印 1 2 3
類數組對象
JavaScript中,數組是一個特殊的對象,其property名為正整數,且其length屬性會隨着數組成員的增減而發生變化,同時又從Array構造函數中繼承了一些用於進行數組操作的方法。而對於一個普通的對象來說:
如果它的所有property名均為正整數,同時也有相應的length屬性,那么雖然該對象並不是由Array構造函數所創建的,它依然呈現出數組的行為,在這種情況下,這些對象被稱為“類數組對象”。
形如:
let obj = {
0: 'qzy',
1: 22, 2: false, length: 3 }
類數組對象可以使用Array對象原生方法進行操作。
遍歷
沿用上述對象進行操作
forEach
Array.prototype.forEach.call(obj, function(el, index){
console.log(index, ' => ', el) })
map
Array.prototype.map.call(obj, function(el, index){
console.log(index, ' => ', el) })
注意: 類數組對象不支持使用for-of進行遍歷,否則會報錯: [Symbol.iterator] is not a function
增刪截取操作
沿用上述對象進行操作
Array.prototype.join.call(obj, '-') // qzy-22-false
Array.prototype.slice.call(obj, 1, 2) // [22] Array.prototype.push.call(obj, 5) // Object {0: "qzy", 1: 22, 2: false, 3: 5, length: 4}
String也是一個類數組對象
由於字符串對象也存在length,且序號從0開始增加,因此字符串也可以看做一個只讀的類數組對象,這意味着String對象可以使用Array的所有原型方法。
let str = 'hello world'
console.log(Array.prototype.slice.call(str, 0, 5)) // ["h", "e", "l", "l", "o"]
String也可以使用for-of進行遍歷
let str = 'hello world'
for (const s of str) { console.log(s) }
String獨有方法
除了使用Array原型對象的方法,String還包含其他一些自己獨有的方法:
與Array使用方法相同的方法
搜索: indexOf()、lastIndexOf()、concat()
轉換
toLowerCase()、toUpperCase()
截取
substr(start, len)
substring(start, end)
slice(start, end)
let str = 'hello world'
let ret1 = str.substr(6, 5) // "world" let ret2 = str.substring(6, 11) // "world" let ret3 = str.slice(3, 8) // "lo wo"
substring 是以兩個參數中較小一個作為起始位置,較大的參數作為結束位置。
slice 是第一參數為起始位置,第二參數為結束位置,如果結束位置小於起始位置返回空字符串
console.log(str.substring(11, 6) === str.substring(6, 11)) // true
接收負數為參數時:
- slice會將它字符串的長度與對應的負數相加,結果作為參數;
- substr則僅僅是將第一個參數與字符串長度相加后的結果作為第一個參數;
- substring則干脆將負參數都直接轉換為0。
let str = 'hello world'
let ret1 = str.substr(-5) // "world" let ret2 = str.substr(-5, 3) // "wor" let ret3 = str.substring(6, -1) // "hello" let ret4 = str.slice(6, -1) // "worl" console.log(ret1 === str.substr(str.length - 5)) // true console.log(ret2 === str.substr(str.length - 5, 3)) // true console.log(ret3 === str.substring(6, 0)) // true console.log(ret4 === str.slice(6, str.length - 1)) // true
正則
- match()
- replace()
- search()
let str = 'hello world'
let ret0 = str.match(/r/) // 非全局搜索,返回匹配的第一個字符串數組(length為1),包括index和input let ret1 = str.match(/o/g) // 全局搜索,返回匹配的字符串數組,length為搜索到的匹配正則表達式的長度 let ret2 = str.replace(/o/g, 'e') // 全局替換 let ret3 = str.replace(/O/i, 'e') // 不區分大小寫,只替換搜索到的第一個字串 let ret4 = str.search(/l/) // 返回搜索到的第一個匹配字串的索引 let ret5 = str.search(/l/g) // 全局無效,同上 console.log(ret0) // ["r", index: 8, input: "hello world"] console.log(ret1) // ["o", "o"] console.log(ret2) // "helle werld" console.log(ret3) // "helle world" console.log(ret4) // 2 console.log(ret5) // 2 console.log(str) // 不改變源字符串 'hello world'
轉化
Map => Object
let mapObj = new Map([ ['a', 1], ['b', 2], ['c', 3] ]) let obj = {} for (const item of mapObj) { obj[item[0]] = item[1] } console.log(obj)
Set => Array
let setObj = new Set([1, 2, 3]) let arr = [] for (const item of setObj) { arr.push(item) } console.log(arr)
Array => String
arr.join(separator)
['a', 'b', 'c', 'd', 'e'].join('') // toLocaleString 、toString 、valueOf:可以看作是join的特殊用法,不常用
String => Array
str.split(separator)
'hello world'.split(' ') // ["hello", "world"]
```> 在使用js編程的時候,常常會用到集合對象,集合對象其實是一種泛型,在js中沒有明確的規定其內元素的類型,但在強類型語言譬如Java中泛型強制要求指定類型。
> ES6引入了iterable類型,Array,Map,Set都屬於iterable類型,它們可以使用for...of循環來遍歷,都內置forEach方法。
# 數組
## 遍歷
### 普通遍歷
最簡單的一種,也是使用頻率最高的一種。
```java
let arr = ['a', 'b', 'c', 'd', 'e'] for (let i = 0; i < arr.length; i++) { console.log(i, ' => ', arr[i]) }
優化: 緩存數組長度:
let arr = ['a', 'b', 'c', 'd', 'e'] for (let i = 0, len = arr.length; i < len; i++) { console.log(i, ' => ', arr[i]) }
使用臨時變量,將長度緩存起來,避免重復獲取數組長度,當數組較大時優化效果才會比較明顯。
for-in
這個循環很多人愛用,但實際上,經分析測試,在眾多的循環遍歷方式中它的效率是最低的。
let arr = ['a', 'b', 'c', 'd', 'e'] for (let i in arr) { console.log(i, ' => ', arr[i]) }
for-of
這種方式是es6里面用到的,性能要好於forin,但仍然比不上普通for循環。
let arr = ['a', 'b', 'c', 'd', 'e'] let index = 0 for (let item of arr) { console.log(index++, ' => ', item) }
forEach
數組自帶的foreach循環,使用頻率較高,實際上性能比普通for循環弱。
let arr = ['a', 'b', 'c', 'd', 'e'] arr.forEach((v, k) => { console.log(k, ' => ', v) })
forEach接受第三個參數,指向原數組,沒有返回值,對其進行操作會改變原數組對象
let ary = [12, 23, 24, 42, 1] let res = ary.forEach((item, index, input) => { input[index] = item * 10 }) console.log(res) //-->undefined console.log(ary) //-->會對原來的數組產生改變
如果版本低的瀏覽器不兼容(IE8-),可以自定義方法實現:
/**
* forEach遍歷數組
* @param callback [function] 回調函數;
* @param context [object] 上下文;
*/
Array.prototype.myForEach = function (callback,context) { context = context || window; if('forEach' in Array.prototype) { this.forEach(callback,context) return } // IE6-8下自己編寫回調函數執行的邏輯 for(let i = 0,len = this.length; i < len; i++) { callback && callback.call(context, this[i], i, this) } } let arr = [12, 23, 24, 42, 1] arr.myForEach((v, k) => { console.log(k, ' => ', v) })
map
map會返回一個全新的數組,同樣接受第三個參數,如果對其進行操作會改變原數組。
let ary = [12, 23, 24, 42, 1] let res = ary.map((item, index, input) => { return item * 10 }) console.log(res) //-->[120,230,240,420,10] console.log(ary) //-->[12,23,24,42,1]
如果版本低的瀏覽器不兼容(IE8-),可以自定義方法實現:
/**
* map遍歷數組
* @param callback [function] 回調函數;
* @param context [object] 上下文;
*/
Array.prototype.myMap = function myMap(callback,context){ context = context || window if('map' in Array.prototype) { return this.map(callback, context) } //IE6-8下自己編寫回調函數執行的邏輯 let newAry = [] for(var i = 0,len = this.length; i < len; i++) { if(typeof callback === 'function') { var val = callback.call(context, this[i], i, this) newAry[newAry.length] = val } } return newAry } arr.myMap((v, k) => { console.log(k, ' => ', v) })
過濾
filter
對數組中的每個元素都執行一次指定的函數(callback),並且創建一個新的數組,該數組元素是所有回調函數執行時返回值為 true 的原數組元素。它只對數組中的非空元素執行指定的函數,沒有賦值或者已經刪除的元素將被忽略,同時,新創建的數組也不會包含這些元素。
let arr = [12, 5, 8, 130, 44] let ret = arr.filter((el, index, array) => { return el > 10 }) console.log(ret) // [12, 130, 44]
map
map也可以作為過濾器使用,不過返回的是對原數組每項元素進行操作變換后的數組,而不是每項元素返回為true的元素集合。
let strings = ["hello", "Array", "WORLD"]
function makeUpperCase(v) { return v.toUpperCase() } let uppers = strings.map(makeUpperCase) console.log(uppers) // ["HELLO", "ARRAY", "WORLD"]
some
對數組中的每個元素都執行一次指定的函數(callback),直到此函數返回 true,如果發現這個元素,some 將返回 true,如果回調函數對每個元素執行后都返回 false ,some 將返回 false。它只對數組中的非空元素執行指定的函數,沒有賦值或者已經刪除的元素將被忽略。
// 檢查是否有數組元素大於等於10:
function isBigEnough(element, index, array) { return (element >= 10) } let passed1 = [2, 5, 8, 1, 4].some(isBigEnough) // passed1 is false let passed2 = [12, 5, 8, 1, 4].some(isBigEnough) // passed2 is true
every
對數組中的每個元素都執行一次指定的函數(callback),直到此函數返回 false,如果發現這個元素,every 將返回 false,如果回調函數對每個元素執行后都返回 true ,every 將返回 true。它只對數組中的非空元素執行指定的函數,沒有賦值或者已經刪除的元素將被忽略。
// 測試是否所有數組元素都大於等於10:
function isBigEnough(element, index, array) { return (element >= 10) } let passed1 = [12, 5, 8, 1, 4].every(isBigEnough) // passed1 is false let passed2 = [12, 15, 18, 11, 14].every(isBigEnough) // passed2 is true
排序
let arr = ['a', 1, 'b', 3, 'c', 2, 'd', 'e'] console.log(arr) // ["a", 1, "b", 3, "c", 2, "d", "e"] console.log(arr.reverse()) // 反轉元素(改變原數組) // ["e", "d", 2, "c", 3, "b", 1, "a"] console.log(arr.sort()) // 對數組元素排序(改變原數組) // [1, 2, 3, "a", "b", "c", "d", "e"] console.log(arr) // [1, 2, 3, "a", "b", "c", "d", "e"]
sort自定義排序
let arr = [1, 100, 52, 6, 88, 99] let arr1 = arr.sort((a, b) => a-b) // 從小到大排序 console.log(arr1) // [1, 6, 52, 88, 99, 100] let arr2 = arr.sort((a, b) => b-a) // 從大到小排序 console.log(arr2) // [100, 99, 88, 52, 6, 1] console.log(arr) // 原數組也發生改變
搜索
let arr = [12, 5, 4, 8, 1, 4] arr.indexOf(4) // 2,從前往后搜索,返回第一次搜索到的數組下標,搜索不到返回-1 arr.lastIndexOf(4) // 5,從后往前搜索,返回第一次搜索到的數組下標,搜索不到返回-1 arr.indexOf(0) // -1
增刪、清空操作
添加元素
let arr = ['a', 'b', 'c', 'd', 'e'] arr.push(10, 11) // 模仿棧進行操作,往數組末尾添加一個或多個元素(改變原數組) arr.unshift(0, 1) // 模仿隊列進行操作,往數組前端添加一個或多個元素(改變原數組) console.log(arr) // [0, 1, "a", "b", 'c', "d", "e", 10, 11]
刪除元素
arr.pop() // 移除最后一個元素並返回該元素值(改變原數組)
arr.shift() // 移除最前一個元素並返回該元素值,數組中元素自動前移(改變原數組)
console.log(arr) // ["b", "c", "d"]
清空數組
將數組的length設置為0即可
let arr = ['a', 1, 'b', 3, 'c', 2, 'd', 'e'] arr.length = 0
length詳解:
- 因為數組的索引總是由0開始,所以一個數組的上下限分別是:0和length-1;
- 當length屬性被設置得更大時,整個數組的狀態事實上不會發生變化,僅僅是length屬性變大;
- 當length屬性被設置得比原來小時,則原先數組中索引大於或等於length的元素的值全部被丟失。
splice
既可以刪除也可以添加元素
let arr = ['a', 'b', 'c', 'd', 'e'] arr.splice(2, 1, 1,2,3) console.log(arr) // ["a", "b", 1, 2, 3, "d", "e"]
splice(start, len, elems) : 刪除並添加元素(改變原數組)
- start: 起始位置
- len: 刪除元素的長度
- elems: 添加的元素隊列
- 幾種形式:
- splice(start, 0, elems) : 從start位置添加元素
- splice(start, len) : 從start位置刪除len個元素
截取、合並與拷貝
let arr = ['a', 'b', 'c', 'd', 'e'] let arr1 = arr.slice(1, 2) // 以數組的形式返回數組的一部分,注意不包括 end 對應的元素,如果省略 end 將復制 start 之后的所有元素(返回新數組) let arr2 = arr.concat([1,2,3]); // 將多個數組(也可以是字符串,或者是數組和字符串的混合)連接為一個數組(返回新數組) console.log(arr) // ["a", "b", "c", "d", "e"] console.log(arr1) // ["b"] console.log(arr2) // ["a", "b", "c", "d", "e", 1, 2, 3]
其實
slice
和concat
也可以作為數組的拷貝方法:
arr.slice(0) // 返回數組的拷貝數組,注意是一個新的數組,不是指向
arr.concat() // 返回數組的拷貝數組,注意是一個新的數組,不是指向
Map
Map是一組鍵值對的結構,具有極快的查找速度。
創建
方法一: 創建的時候初始化
let mapObj = new Map([
['a', 1], ['b', 2], ['c', 3] ]) console.log(mapObj.size) // 3
方法二: 創建空Map,之后添加元素
let mapObj = new Map()
mapObj.set('a', 1) mapObj.set('b', 2) mapObj.set('c', 3) console.log(mapObj.size) // 3
注意: Map對象的長度不是length,而是size
基礎操作
Map對象的創建、添加元素、刪除元素...
mapObj.set('a', 1) // 添加元素
mapObj.delete('d') // 刪除指定元素 mapObj.has('a') // true mapObj.get('a') // 1
遍歷
使用上面創建的Map進行操作
forEach
同數組的forEach遍歷,三個參數分別代表: value、key、map本身
mapObj.forEach((e, index, self) => {
console.log(index, ' => ', e)
})
打印出:
a => 1
b => 2
c => 3
for-of
for (const e of mapObj) {
console.log(e)
}
打印出:
["a", 1]
["b", 2]
["c", 3]
注意: for-of遍歷出來的是一個數組,其中e[0]為key,e[1]為value
Set
Set和Map類似,但set只存儲key,且key不重復。
創建
方法一: 創建的時候初始化
let setObj = new Set([1, 2, 3]) console.log(setObj.size)
方法二: 創建空Map,之后添加元素
let setObj = new Set()
setObj.add(1)
setObj.add(2) setObj.add(3) console.log(setObj.size)
注意: Map對象的長度不是length,而是size
基礎操作
let s = new Set([1, 2, 3]) s.add(3) // 由於key重復,添加不進 s.delete(3) // 刪除指定key console.log(s) // 1 2
遍歷
使用上面創建的Set進行操作
forEach
Set與Array類似,但Set沒有索引,因此回調函數的前兩個參數都是元素本身
s1.forEach(function (element, sameElement, set) {
console.log(element) // element === sameElement }) // 打印 1 2 3
for-of
for (const item of s1) {
console.log(item)
}
// 打印 1 2 3
類數組對象
JavaScript中,數組是一個特殊的對象,其property名為正整數,且其length屬性會隨着數組成員的增減而發生變化,同時又從Array構造函數中繼承了一些用於進行數組操作的方法。而對於一個普通的對象來說:
如果它的所有property名均為正整數,同時也有相應的length屬性,那么雖然該對象並不是由Array構造函數所創建的,它依然呈現出數組的行為,在這種情況下,這些對象被稱為“類數組對象”。
形如:
let obj = {
0: 'qzy',
1: 22, 2: false, length: 3 }
類數組對象可以使用Array對象原生方法進行操作。
遍歷
沿用上述對象進行操作
forEach
Array.prototype.forEach.call(obj, function(el, index){
console.log(index, ' => ', el) })
map
Array.prototype.map.call(obj, function(el, index){
console.log(index, ' => ', el) })
注意: 類數組對象不支持使用for-of進行遍歷,否則會報錯: [Symbol.iterator] is not a function
增刪截取操作
沿用上述對象進行操作
Array.prototype.join.call(obj, '-') // qzy-22-false
Array.prototype.slice.call(obj, 1, 2) // [22] Array.prototype.push.call(obj, 5) // Object {0: "qzy", 1: 22, 2: false, 3: 5, length: 4}
String也是一個類數組對象
由於字符串對象也存在length,且序號從0開始增加,因此字符串也可以看做一個只讀的類數組對象,這意味着String對象可以使用Array的所有原型方法。
let str = 'hello world'
console.log(Array.prototype.slice.call(str, 0, 5)) // ["h", "e", "l", "l", "o"]
String也可以使用for-of進行遍歷
let str = 'hello world'
for (const s of str) { console.log(s) }
String獨有方法
除了使用Array原型對象的方法,String還包含其他一些自己獨有的方法:
與Array使用方法相同的方法
搜索: indexOf()、lastIndexOf()、concat()
轉換
toLowerCase()、toUpperCase()
截取
substr(start, len)
substring(start, end)
slice(start, end)
let str = 'hello world'
let ret1 = str.substr(6, 5) // "world" let ret2 = str.substring(6, 11) // "world" let ret3 = str.slice(3, 8) // "lo wo"
substring 是以兩個參數中較小一個作為起始位置,較大的參數作為結束位置。
slice 是第一參數為起始位置,第二參數為結束位置,如果結束位置小於起始位置返回空字符串
console.log(str.substring(11, 6) === str.substring(6, 11)) // true
接收負數為參數時:
- slice會將它字符串的長度與對應的負數相加,結果作為參數;
- substr則僅僅是將第一個參數與字符串長度相加后的結果作為第一個參數;
- substring則干脆將負參數都直接轉換為0。
let str = 'hello world'
let ret1 = str.substr(-5) // "world" let ret2 = str.substr(-5, 3) // "wor" let ret3 = str.substring(6, -1) // "hello" let ret4 = str.slice(6, -1) // "worl" console.log(ret1 === str.substr(str.length - 5)) // true console.log(ret2 === str.substr(str.length - 5, 3)) // true console.log(ret3 === str.substring(6, 0)) // true console.log(ret4 === str.slice(6, str.length - 1)) // true
正則
- match()
- replace()
- search()
let str = 'hello world'
let ret0 = str.match(/r/) // 非全局搜索,返回匹配的第一個字符串數組(length為1),包括index和input let ret1 = str.match(/o/g) // 全局搜索,返回匹配的字符串數組,length為搜索到的匹配正則表達式的長度 let ret2 = str.replace(/o/g, 'e') // 全局替換 let ret3 = str.replace(/O/i, 'e') // 不區分大小寫,只替換搜索到的第一個字串 let ret4 = str.search(/l/) // 返回搜索到的第一個匹配字串的索引 let ret5 = str.search(/l/g) // 全局無效,同上 console.log(ret0) // ["r", index: 8, input: "hello world"] console.log(ret1) // ["o", "o"] console.log(ret2) // "helle werld" console.log(ret3) // "helle world" console.log(ret4) // 2 console.log(ret5) // 2 console.log(str) // 不改變源字符串 'hello world'
轉化
Map => Object
let mapObj = new Map([ ['a', 1], ['b', 2], ['c', 3] ]) let obj = {} for (const item of mapObj) { obj[item[0]] = item[1] } console.log(obj)
Set => Array
let setObj = new Set([1, 2, 3]) let arr = [] for (const item of setObj) { arr.push(item) } console.log(arr)
Array => String
arr.join(separator)
['a', 'b', 'c', 'd', 'e'].join('') // toLocaleString 、toString 、valueOf:可以看作是join的特殊用法,不常用
String => Array
str.split(separator)
'hello world'.split(' ') // ["hello", "world"]