[toc]
> 數組 API:[https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global\_Objects/Array](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array)
# 題1、如何獲取數組中元素的個數?
答:length。
比如:
~~~
[1,2,34].length
~~~
# 題2、shift、unshift、pop、push 四個方法是干什么用的?
答:shift:取出數組中的第 1 個元素,并且將這個元素從數組中刪除。(彈出)
注意:通過下標 0也可以獲取數組中的第一個元素,arr[0],區別是這種不會刪除第1個元素
unshift: 從數組的前面向數組中添加一個元素。
比如:[1,2,3].unshift(4) --> [4,1,2,3]
pop:取出數組中最后一個元素,并且將這個元素從數組中刪除。(彈出)
注意:通過下標也可以獲取數組中最后一企鮮紅:arr[arr.length-1],區別是這種不會刪除最后一個元素
push:從數組的后面向數組中添加一個元素。
比如:[1,2,3].push(0) --> [1,2,3,0]
# 題3、如何創建一個擁有 10 個元素的數組?
答:let arr = new Array(10)
知識點復習:創建數組至少有兩種方法:
~~~
let arr = new Array() // 創建空數組
let arr1 = [] // 創建空數組
~~~
# 題4、如何用數組模擬棧結構?
答:棧(zhan)是一種數據結構,特點:后進先出(LIFO:Last In First Out)。

可以使用 push 和 pop 實現入棧和出棧操作來模擬棧。
也可以使用 shift 和 unshift 實現入棧和出棧操作來模擬棧。
# 題5、如何用數組模擬隊列結構?
答:隊列(queue)是一種數組,特點:前進前出(FIFO:Fist In First Out)。

可以使用 push 和 shift 方法實現入隊和出隊來模擬隊列。
也可以使用 unshift 和 pop 方法實現入隊和出隊來模擬隊列。
# 題6、如何獲取數組中最后一個元素的值?
答:
方法一、下標 arr[ arr.length - 1] (只獲取不會刪除最后一個元素)
方法二、arr.pop() (獲取并刪除最后一個元素)
# 題7、如何把數組轉成一個字符串?
答:方法一、join 默認使用,隔開,也可以使用其他字符
方法二、toString , 只能使用 , 隔開
# 題8、如何截取數組,比如:從數組中截取出第 2~4 個元素?
答:方法一、splice [1,2,3,4,5,6,7,8].splice(1, 5) 開始下標 ~ 截取長度 ,修改原數組
方法二、slice , [1,2,3,4,5,6,7,8].slice(1, 5) , 開始下標 ~ 結束下標 ,不修改原數組
# 題9、如何刪除數組中的元素?
答:splice。 比如刪除第2個元素: arr.splice(1,1)
# 題10、如何對數組進行排序?
答:sort。
sort 可以用來對數組進行排序,但是使用時要注意:默認是 `按字符串` 進行排序的!!

如何才能 `按數字` 來進行排序?
答:添加一個回調函數做為參數,這個回調函數有兩個參數。

回調函數可以簡寫為箭頭函數:

# 題11、什么是按引用傳值?哪些變量是按引用傳值?
答:把一個變量在內存中的地址(引用)傳過去。
對象類型(包含數組)的數據都是按引用傳值的。

特點:a和b現在操作的是內存中的同一個數組。
比如:

總結:
1. 對象和數組在傳值是是按引用傳值。(傳完之后,多個變量名操作的是同一個值)
2. 其他類型(數字、字符串、布爾等)不是按引用傳值,其他類型是復制一份然后傳值,(傳完之后,彼此互不影響,各操作各的)
# 題12、引用的擴展面試題1?
請說出以下代碼的輸出結果
代碼一、
~~~
let a = "abc"
let b = a // 不是引用傳值,把 a 復制一份傳給 b ,b 和 a 是兩個獨立的變量
b = 'hello' // b 和 a 是兩個獨立的變量,修改 b 不影響 a
console.log(a) // 輸出 abc
console.log(b) // 輸出 hello
~~~
代碼二、
~~~
let a = [1,2,3]
let b = a // 數組是按引用傳值,把 a 在內存中的地址傳給 b ,a 和 b 指向同一個數組
b[1] = 100 // 修改 b 中的值, a 也會改變,因為 a 和 b 指向同一個數組
console.log(a) // 輸出 [1,100,3]
console.log(b) // 輸出 [1,100,3]
~~~
代碼三、
~~~
let a = {name:'tom',age:10}
let b = a // 對象是引用傳值,把 a 在內存中的地址傳給 b ,a 和 b 指向同一個對象
b.age++ // 修改 b 對象就是修改 a 對象
console.log(a.age) // 輸出 11
console.log(b.age) // 輸出 11
~~~
# 題13、引用的擴展面試題2?
說出以下代碼的輸出結果:
代碼一、
~~~
let a = 'abc'
function toUp(a) {
a = a.toUpperCase() // 這里的 a 和函數外面的 a 沒有任何關系
}
toUp(a) // 不是按引用傳遞(按值傳遞),把 a 的值復制一份傳到函數中,函數中的變量和 a 完全沒有關系
console.log(a) // 輸出 abc
~~~
代碼二、
~~~
let a = [1,2,3]
function toUp(a) {
a[0] = 100 // 這個a 就是外面的 a ,所以修改這個,就是修改外面的 a
}
toUp(a) // 數組和對象都是按引用傳遞的,也就是說,函數中的 a 和外面的 a 是同一個 a
console.log(a) // 輸出 [100,2,3]
~~~
上面兩段代碼函數參數中的 a 會給同學生造成誤解,以為是同一個 a,其實 函數參數名是任意的,
代碼一、
~~~
let a = 'abc'
function toUp(x) {
x = x.toUpperCase() // 這里的 a 和函數外面的 a 沒有任何關系
}
toUp(a) // 不是按引用傳遞(按值傳遞),把 a 的值復制一份傳到函數中,函數中的變量和 a 完全沒有關系
console.log(a) // 輸出 abc
~~~
代碼二、
~~~
let a = [1,2,3]
function toUp(x) {
x[0] = 100 // 這個a 就是外面的 a ,所以修改這個,就是修改外面的 a
}
toUp(a) // 數組和對象都是按引用傳遞的,也就是說,函數中的 a 和外面的 a 是同一個 a
console.log(a) // 輸出 [100,2,3]
~~~
當然還有一種情況:這個情況和引用沒有關系,`變量作用域` 的問題:
~~~
let a = 'abc'
function toUp() {
a = a.toUpperCase() // 這個 a 就是外面的 a
}
toUp()
console.log(a) // 輸出 ABC
~~~
# 題14、數組是按引用傳遞的,無法直接復制,那么應該如何復制(克隆)出一個新數組?
答:
方法一、(ES6)可以使用 ES6 中展開(...)運算符。(一維好使)
~~~
let a = [1,2,3,4]
let b = [...a] // 把 a 中的元素展開,賦給 b (復制了一份),a 和 b 是兩個獨立 的數組
b[0] = 100 // 不影響 a
console.log(a) // [1,2,3,4]
console.log(b) // [100,2,3,4]
~~~
方法二、先轉字符串再轉回數組( **幾維都好使**)
~~~
let a = [1,2,3,4]
let b = JSON.parse(JSON.stringify(a)) // 復制克隆一份
b[0] = 100
console.log(a)
console.log(b)
~~~
方法三、slice(一維好使)
~~~
let a = [1,2,3,4]
let b = a.slice()
~~~
方法四、(ES6)(一維好使)
~~~
let a = [1,2,3,4]
let b = []
Object.assign(b,a) // 把 a 的值克隆一份給b
~~~
# 題15、如何合并兩個數組?
答:
方法一、concat
~~~
let a = [1,2,3]
let b = [3,4,5]
let c = a.concat(b)
~~~
方法二、... (ES6)
~~~
let a = [1,2,3]
let b = [3,4,5]
let c = [...a, ...b]
~~~
# 題16、請說出至少 10 個操作數組的方法?
答:concat:合并數組
join:轉字符串
map:循環并修改數組中每個元素
filter:過濾數組
find:從數組中查找一個元素
findIndex:從數組中查找一個元素的下標
sort:排序
push:從后面添加元素
pop:從后面“彈出”元素
shift:從前面“彈出”元素
unshift:從前面添加元素
slice:截取數組(不刪除)
splice:截取并從數組中刪除
reverse:反轉數組元素的順序
toString:轉成字符串
toLocaleString:轉字符串
forEach:循環數組中的元素
every(判斷都滿足):循環對數組中每個元素執行一個條件判斷,如果所有的判斷都返回 true ,那么最終結果是 true ,只要有一個是 false ,結果就是 false
some(判斷至少有一個滿足):和 every 相反,只要數組中有一個滿足條件就返回 true,如果全都不滿足條件就返回 false
~~~
some 和 every 和對比
let a = [3,4,5,6,7]
// 含義:every(每一個都滿足):是否每一個都大于4
a.every(v=>v>4) // false
// 含義:some(有至少一個滿足):是否有至少一個大于4
a.some(v=>v>4) // true
~~~
reduce:循環處理數組中所有的元素,最后可以把每個結果累加到一起,返回最終結果。要會使用這個函數,首先要明確參數的函數。
~~~
let a = [1,2,3,4,5]
// 參數一x、上一次計算的結果
// 參數二y、循環數組時的當前元素
// 參數三z、當前元素的下標
// 返回值:這一次的計算結果,這個結果會被當作下一次循環的累加結果(第一個參數)
// 比較數組中求和:
// 說明: return x+y 含義:上一次的累加結果(x) + 當前值,和做為下一次的累加結果
a.reduce( function(x,y,z){ return x+y })
簡寫:
a.reduce((a,b)=>a+b)
~~~
# 題17、有一個數組:['abc','bcd','cd'],如何將數組中每個元素的第 1 個字母變大寫?
答:
~~~
let a = ['abc','bcd','cd']
// 1. 向字符串對象的原型中添加一個方法,這樣所有字符串就可以直接使用這個方法了
String.prototype.ucfirst = function() {
// 轉數組
let arr = this.split("") // ['a','b','c']
// 每1個元素大寫
arr[0] = arr[0].toUpperCase() // ['A','b','c']
// 轉字符
return arr.join("") // 'Abc'
}
// 2.對數組中每個字符串都執行 ucFirst 方法
a = a.map(v=>v.ucfirst())
console.log(a) // ['Abc','Bcd','Cd']
~~~
# 題18、如何對數組去重?能想到幾種方法?
答:
方案一、最簡單的使用 ES6 中的 Set
使用 ES6 中的 Set 這種數據類型。
Set(集合),特點:沒有重復的數據。
思路:1. 先把數組轉成一個集合(重復的數據就刪除了) ---> let s = new Set( 數組 )
2. 把集合轉回數組 ----> [ ...s ]
方案二、(最笨的方法)雙向循環,一個一個判斷