(一)字符串相關
一、獲取查詢字符串
/**
* 獲取url中的查詢字符串的某個值
* @param key 必須參數,查詢字符串中的一個鍵名
* @param url 可選參數,默認爲當前頁面的url
* @returns {string|null}
*/
function getQuery(key,url=document.location.href){
const query = url.split("?").length > 1 ? url.split("?")[1] : null
if(!query)
throw new Error("當前url沒有查詢字符串")
const entries = query.split("&")
for(let i = 0;i < entries.length;i++){
const entry = entries[i].split("=")
if(key === entry[0]){
return entry[1]
}
}
return null
}
二、翻轉字符串
如果需要翻轉一個數組,那麼很簡單,因爲原生的方法就支持實現這個功能。但是,如果需要翻轉一個字符串就需要自己實現了。實現的思路也很簡單,先把字符串轉換爲數組,將數組翻轉,最後將數組轉化爲字符串。
/**
*
* @param str 待翻轉的字符串
* @returns {string} 翻轉後的字符串
*/
function reverseString(str){
str = "" + str
return str.split("").reverse().join("")
}
三、去重字符串相同字符
感覺這個需求在面試中出現的比較多,實現原理:
字符串是可迭代對象,所以可以轉換爲 Set
類型,利用 Set
類型元素唯一性進行去重,然後將 Set
轉換爲數組,最後通過數組方法拼接成字符串。
[...new Set(str)].join("")
(二)數組相關
一、數組去重
數組去重是一個很常見的需求了,在網上也有很多去重的方法,在此介紹兩個簡潔的去重方法。
unique(arr){
if(!Array.isArray(arr))
throw new Error("arr is not a array")
return [...new Set(arr)] //或者 Array.from(new Set(arr))
}
上面就是利用了 Set
元素的唯一性。
但是,如果數組中存在內容相同的引用類型,那麼這個方法就沒有效果了。
比如:
let arr = [
{name:"jonas",age:18},
{name:"jonas",age:18},
{name:"jonas",age:18}
]
你會發現無論使用上面的方法還是網絡上介紹的數組去重方法,都實現不了這種去重。所以,這時候自己寫了一個方法用於解決這個問題(見下面)。
二、數組深度去重
對於基本數據類型的去重很簡單,就是上面的一行代碼就解決了,然而複雜的是引用類型。此處的引用類型主要是指對象和數組,所以,問題就變成兩個:①去重內容相同的對象②去重內容相同的數組。
因爲數組和對象的特徵不同,存儲數據的方式也不同,所以第一件事就是將數組和對象區分開來。
/**
* 獲取一個值的類型
* @param target
* @returns {string} 返回這個值的類型。如果是數組,則返回 "Array";是對象返回 "Object"
*/
function getType(target) {
return Object.prototype.toString.call(target).slice(8,-1)
}
接下來的問題就是判斷兩個對象中的內容是否完全一致了。
/**
* 判斷兩個對象的內容是否完全一致,返回布爾值
* @param a
* @param b
* @returns {boolean}
*/
function objUnique(a,b) {
//限制兩個參數都是對象
if(getType(a) !== 'Object' && getType(b) !== 'Object')
return false
//獲取其中一個對象的屬性
let keyList = Object.keys(a)
for(let i = 0;i < keyList.length;i++){
//獲取鍵名
let propName = keyList[i]
//處理嵌套
if(getType(a[propName]) === 'Object' && getType(b[propName]) === 'Object'){
objUnique(a[propName],b[propName])
}else if(getType(a[propName]) === 'Array' && getType(b[propName]) === 'Array'){
arrUnique(a[propName],b[propName])
}else if(a[propName] !== b[propName]){
//存在一對鍵值對不同,則表示兩個對象不同
return false
}
}
return true
}
/**
* 判斷兩個數組的內容是否完全一致,返回布爾值
* @param a
* @param b
* @returns {boolean}
*/
function arrUnique(a, b) {
//限制兩個參數都是數組
if(getType(a) !== 'Array' && getType(b) !== 'Array')
return false
//如果長度不等,則兩個數組不可能相同
if(a.length !== b.length)
return false
//處理嵌套
for(let i = 0;i < a.length;i++){
if(getType(a[i]) === 'Object' && getType(b[i]) === 'Object'){
objUnique(a[i],b[i])
}else if(getType(a[i]) === 'Array' && getType(b[i]) === 'Array'){
arrUnique(a[i],b[i])
}else if(a[i] !== b[i]){
//存在一個元素不同,則表示兩個數組不同
return false
}
}
return true
}
整合:
/**
* 數組深度去重
* @param arr
* @returns {null|*[]}
*/
function unique(arr) {
//處理異常參數
if(getType(arr) !== 'Array')
throw new Error("arr is not a Array.")
//基本數據類型容器
let commonList = []
//對象收納容器
let objList = []
//數組收納容器
let arrList = []
//數據分類
arr.forEach(item => {
if(getType(item) === 'Object'){
objList.push(item)
}else if(getType(item) === 'Array'){
arrList.push(item)
}else{
commonList.push(item)
}
})
//基本數據類型去重
commonList = Array.from(new Set(commonList))
//對象收納容器去重
for(let i = 0;i < objList.length;i++){
for(let j = i + 1;j < objList.length;j++){
if(objUnique(objList[i],objList[j])){
objList.splice(j,1)
j--
}
}
}
//數組收納容器去重
for(let i = 0;i < arrList.length;i++){
for(let j = i + 1;j < arrList.length;j++){
if(arrUnique(arrList[i],arrList[j])){
arrList.splice(j,1)
j--
}
}
}
//合併收納容器
return [...commonList,...objList,...arrList]
}
三、數組的並集,交集,差集
公共代碼:
let arr1 = [1, 2, 3]
let arr2 = [4, 3, 2]
①並集
let arr = [...new Set([...arr1,...arr2])]
②交集
let arr = arr1.filter(x => arr2.includes(x))
③差集
let arr = arr1.filter(x => !arr2.includes(x))
四、取數組中的最大值與最小值
/**
* 取數組中的最大值與最小值,忽略非數值元素和NaN
* @param arr
* @return {{min: *, max: *}|null}
*/
function minAndMax(arr) {
//規範類型
function getType(obj) {
return Object.prototype.toString.call(obj).slice(8,-1)
}
if(getType(arr) !== "Array")
throw new Error("arr is not array")
let min
let max
let flag = 0
for(let i = 0;i < arr.length;i++){
let current = arr[i]
//剔除非法數據
if(getType(current) !== "Number" || Number.isNaN(current)){
continue
}
if(!flag){
min = current
max = current
flag++
}
if(current > max)
max = current
if(current < min)
min = current
}
return {min,max}
}
五、數組的扁平化
扁平化,就是將多維數組轉換爲一維數組。
在 ES6
中有提供了一個方法用於扁平化:
let arr = [1,[2,[3,[4]]]]
let result = arr.flat(Infinity) //參數代表扁平層數,默認爲1
(三)對象相關
一、對象或數組的深拷貝
JSON.parse(JSON.stringify(obj))
(四)數據類型相關
一、準確檢測數據類型
無論是 typeof
還是 instanceof
,都無法很好的準確的檢測一個未知對象的數據類型。所以還是手寫了一個方法:
/**
* 檢測數據類型
* @param obj 待檢測對象
* @returns {string} 返回具體的類型(首字母大寫)
*/
function checkType(obj) {
return Object.prototype.toString.call(obj).slice(8,-1)
}
- 如果是對象,則返回
Object
; - 如果是數組,則返回
Array
- 如果是字符串,則返回
String
以此類推,該方法還支持 ES6+
的所有數據類型。
二、數據類型轉換
基本類型的轉換就不再此處說了,這裏說的引用類型之間的轉換。
① Map
轉換爲普通對象
/**
* 將map轉換爲普通對象
* @param map
* @return obj
*/
function mapToObj(map) {
if(getType(map) !== "Map")
throw new Error("map is not a Map")
let obj = {}
map.forEach((value,key) => {
if(getType(key) !== "String")
key = Object.prototype.toString.call(key)
obj[key] = value
})
function getType(obj) {
return Object.prototype.toString.call(obj).slice(8,-1)
}
return obj
}
②對象轉換爲 Map
一行代碼解決:
new Map(Object.entries(obj))
(五)日期相關
一、將日期類型轉換爲yyyy-mm-dd hh:mm:ss 格式
function getDate(date = new Date()) {
const year = date.getFullYear()
const month = date.getMonth() + 1 < 10 ? `0${date.getMonth() + 1}` : date.getMonth() + 1
const day = date.getDate() < 10 ? `0${date.getDate()}` : date.getDate()
const hours = date.getHours() < 10 ? `0${date.getHours()}` : date.getHours()
const min = date.getMinutes() < 10 ? `0${date.getMinutes()}` : date.getMinutes()
const seconds = date.getSeconds() < 10 ? `0${date.getSeconds()}` : date.getSeconds()
return `${year}-${month}-${day} ${hours}:${min}:${seconds}`
}
(未完,一直更)