14個你必須知道的JavaScript函數
1、確定任意對象的具體類型眾所周知,JavaScript 中有六種原始數據類型(Boolean、Number、String、Null、Undefined、Symbol)和一個對象數據類型。但是你知道對象數據類型可以細分為很多種子類型嗎?一個對象可能是數組、函數、map等,如果我們要獲取對象的具體類型,應該怎么做呢?代碼:
function toRawType (value) {
let _toString = Object.prototype.toString;
let str = _toString.call(value)
return str.slice(8, -1)
}
解釋ECMAScript 有以下規則:
對于不同的對象,調用 Object.prototype.toString() 時會返回不同的結果。
而且,Object.prototype.toString() 的返回值總是‘[object’+‘tag’+‘]’的格式。如果我們只想要中間的標簽,我們可以通過正則表達式或者String.prototype.slice()刪除兩邊的字符。例子:
toRawType(null)
// "Null"
toRawType(/sdfsd/)
//"RegExp"
2、緩存函數計算結果如果有這樣的功能:
function computed(str) {
// Suppose the calculation in the funtion is very time consuming
console.log('2000s have passed')
return 'a result'
}
我們要緩存函數操作的結果, 稍后調用時,如果參數相同,則不再執行該函數,而是直接返回緩存中的結果。我們能做什么?代碼:
function cached(fn){
// Create an object to store the results returned after each function execution.
const cache = Object.create(null);
// Returns the wrapped function
return function cachedFn (str) {
// If the cache is not hit, the function will be executed
if ( !cache[str] ) {
let result = fn(str);
// Store the result of the function execution in the cache
cache[str] = result;
}
return cache[str]
}
}
例子:
3、實現Array.prototype.map這是 JavaScript 中一個有用的內置方法,你應該能夠自己實現此功能。代碼:
const selfMap = function (fn, context) {
let arr = Array.prototype.slice.call(this)
let mappedArr = Array()
for (let i = 0; i < arr.length; i++) {
if (!arr.hasOwnProperty(i)) continue;
mappedArr[i] = fn.call(context, arr[i], i, this)
}
return mappedArr
}
Array.prototype.selfMap = selfMap;
例子:
4、實現Array.prototype.filter這是 JavaScript 中一個有用的內置方法,你應該能夠自己實現此功能。代碼:
const selfFilter = function (fn, context) {
let arr = Array.prototype.slice.call(this)
let filteredArr = []
for (let i = 0; i < arr.length; i++) {
if(!arr.hasOwnProperty(i)) continue;
fn.call(context, arr[i], i, this) && filteredArr.push(arr[i])
}
return filteredArr
}
Array.prototype.selfFilter = selfFilter;
例子:
5、實現 Array.prototype.some這是 JavaScript 中一個有用的內置方法,你應該能夠自己實現此功能。代碼:
const selfSome = function (fn, context) {
let arr = Array.prototype.slice.call(this)
if(!arr.length) return false
for (let i = 0; i < arr.length; i++) {
if(!arr.hasOwnProperty(i)) continue;
let res = fn.call(context,arr[i],i,this)
if(res)return true
}
return false
}
Array.prototype.selfSome = selfSome;
例子:
6、實現 Array.prototype.reduce這是 JavaScript 中一個有用的內置方法,你應該能夠自己實現此功能。代碼:
const selfReduce = function (fn, initialValue) {
let arr = Array.prototype.slice.call(this)
let res
let startIndex
if (initialValue === undefined) {
for (let i = 0; i < arr.length; i++) {
if (!arr.hasOwnProperty(i)) continue
startIndex = i
res = arr[i]
break
}
} else {
res = initialValue
}
for (let i = ++startIndex || 0; i < arr.length; i++) {
if (!arr.hasOwnProperty(i)) continue
res = fn.call(null, res, arr[i], i, this)
}
return res
}
Array.prototype.selfReduce = selfReduce;
例子:
7、實現 Array.prototype.flat代碼:
const selfFlat = function (depth = 1) {
let arr = Array.prototype.slice.call(this)
if (depth === 0) return arr
return arr.reduce((pre, cur) => {
if (Array.isArray(cur)) {
return [...pre, ...selfFlat.call(cur, depth - 1)]
} else {
return [...pre, cur]
}
}, [])
}
Array.prototype.selfFlat = selfFlat;
例子:
8、柯里化柯里化是一種將具有多個參數的函數評估為具有單個參數的函數序列的技術。換句話說,當一個函數不是一次接受所有參數時,而是接受第一個參數并返回一個新函數,該函數接受第二個參數并返回一個新函數,該函數接受第三個參數,依此類推,直到所有參數都已履行。那就是我們將函數調用 add(1,2,3) 轉換為 add(1)(2)(3) 。通過使用這種技術,可以輕松地配置和重用小塊。為什么有用?
· 柯里化可以幫助您避免一次又一次地傳遞相同的變量。
· 它有助于創建高階函數,它對事件處理非常有幫助。
· 小部件可以輕松配置和重用。
讓我們看一個簡單的添加函數。它接受三個操作數作為參數,并返回所有三個操作數的總和作為結果。
function add(a,b,c){
return a + b + c;
}
你可以用太少(結果奇怪)或太多(多余的參數被忽略)來調用它。
add(1,2,3) --> 6
add(1,2) --> NaN
add(1,2,3,4) --> 6 //Extra parameters will be ignored.
如何將現有函數轉換為 curried 版本?代碼:
function curry(fn) {
if (fn.length <= 1) return fn;
const generator = (...args) => {
if (fn.length === args.length) {
return fn(...args)
} else {
return (...args2) => {
return generator(...args, ...args2)
}
}
}
return generator
}
例子:
9、去抖動去抖動只不過是減少不必要的耗時計算,以提高瀏覽器性能。在某些情況下,某些功能需要更多時間來執行某個操作。例如,以電子商務網站上的搜索欄為例。假設用戶想要獲得“Tutorix 學習套件”。他在搜索欄中鍵入產品的每個字符。輸入每個字符后,從瀏覽器到服務器都會進行一次 Api 調用,以獲取所需的產品。由于他想要“Tutorix 學習套件”,用戶必須從瀏覽器到服務器進行 17 次 Api 調用。想象一個場景,當數百萬人進行相同的搜索從而調用數十億個 Api 時。所以一次調用數十億個 Api 肯定會導致瀏覽器性能變慢。為了減少這個缺點,去抖動出現了。在這種情況下,去抖動將在兩次擊鍵之間設置一個時間間隔,假設為 2 秒。如果兩次擊鍵之間的時間超過 2 秒,則只會進行 Api 調用。在這 2 秒內,用戶可以輸入至少一些字符,從而減少 Api 調用的這些字符。由于 Api 調用減少,瀏覽器性能將提高。必須注意,每次擊鍵都會更新 Debouncing 功能。代碼:
const debounce = (func, time = 17, options = {
leading: true,
context: null
}) => {
let timer;
const _debounce = function (...args) {
if (timer) {
clearTimeout(timer)
}
if (options.leading && !timer) {
timer = setTimeout(null, time)
func.apply(options.context, args)
}else{
timer = setTimeout(() => {
func.apply(options.context, args)
timer = null
}, time)
}
};
_debounce.cancel = function () {
clearTimeout(timer)
timer = null
};
return _debounce
};
10、 節流節流將以這樣一種方式更改函數,即它可以在一個時間間隔內最多觸發一次。例如,無論用戶單擊按鈕多少次,限制將在 1000 毫秒內僅執行一次該功能。
代碼:
const throttle = (func, time = 17, options = {
leading: true,
trailing: false,
context: null
}) => {
let previous = new Date(0).getTime()
let timer;
const _throttle = function (...args) {
let now = new Date().getTime();
if (!options.leading) {
if (timer) return
timer = setTimeout(() => {
timer = null
func.apply(options.context, args)
}, time)
} else if (now - previous > time) {
func.apply(options.context, args)
previous = now
} else if (options.trailing) {
clearTimeout(timer)
timer = setTimeout(() => {
func.apply(options.context, args)
}, time)
}
};
_throttle.cancel = () => {
previous = 0;
clearTimeout(timer);
timer = null
};
return _throttle
};
11、 延遲加載圖片延遲加載圖片意味著在網站上異步加載圖片——也就是說,在首屏內容完全加載之后,甚至有條件地,只有當它們出現在瀏覽器的視口中時。這意味著如果用戶不一直向下滾動,則放置在頁面底部的圖像甚至不會被加載。代碼:
// getBoundingClientRect
let imgList1 = [...document.querySelectorAll(".get_bounding_rect")]
let num = imgList1.length
let lazyLoad1 = (function () {
let count = 0
return function () {
let deleteIndexList = []
imgList1.forEach((img,index) => {
let rect = img.getBoundingClientRect()
if (rect.top < window.innerHeight) {
img.src = img.dataset.src
// Add picture to delete list after loading successfully
deleteIndexList.push(index)
count++
if (count === num) {
//When all pictures are loaded, unbind scroll event
document.removeEventListener('scroll',lazyLoad1)
}
}
})
// Delete loaded pictures
imgList1 = imgList1.filter((_,index)=>!deleteIndexList.includes(index))
}
})()
12、數組隨機無序我們經常需要打亂一個數組。代碼:
// Randomly select one of all elements after the current element to exchange with the current element
function shuffle(arr) {
for (let i = 0; i < arr.length; i++) {
let randomIndex = i + Math.floor(Math.random() * (arr.length - i));
[arr[i], arr[randomIndex]] = [arr[randomIndex], arr[i]]
}
return arr
}
// Generate a new array, randomly take an element from the original array and put it into the new array
function shuffle2(arr) {
let _arr = []
while (arr.length) {
let randomIndex = Math.floor(Math.random() * (arr.length))
_arr.push(arr.splice(randomIndex, 1)[0])
}
return _arr
}
例子:
13、單例模式單例模式將特定對象的實例數限制為一個,這個單一實例稱為單例模式。單例在需要從單個中心位置協調系統范圍的操作的情況下很有用。一個例子是數據庫連接池。池管理整個應用程序的所有數據庫連接的創建、銷毀和生命周期,確保沒有連接“丟失”。單例減少了對全局變量的需求,這在 JavaScript 中尤為重要,因為它限制了命名空間污染和相關的名稱沖突風險。代碼:
function proxy(func) {
let instance;
let handler = {
construct(target, args) {
if (!instance) {
// Create an instance if there is not exist
instance = Reflect.construct(func,args)
}
return instance
}
}
return new Proxy(func, handler)
}
// example
function Person(name, age) {
this.name = name
this.age = age
}
const SingletonPerson = proxy(Person)
let person1 = new SingletonPerson('zhl', 22)
let person2 = new SingletonPerson('cyw', 22)
console.log(person1 === person2) // true
例子:
14、實現 JSON.stringify這是 JavaScript 中一個有用的內置方法,你應該能夠自己實現此功能。代碼:
const isString = value => typeof value === 'string';
const isSymbol = value => typeof value === 'symbol'
const isUndefined = value => typeof value === 'undefined'
const isDate = obj => Object.prototype.toString.call(obj) === '[object Date]'
const isFunction = obj => Object.prototype.toString.call(obj) === '[object Function]';
const isComplexDataType = value => (typeof value === 'object' || typeof value === 'function') && value !== null;
const isValidBasicDataType = value => value !== undefined && !isSymbol(value);
const isValidObj = obj => Array.isArray(obj) || Object.prototype.toString.call(obj) === '[object Object]';
const isInfinity = value => value === Infinity || value === -Infinity
// Symbol,undefined,function in array will become null
// Infinity,NaN will also become null
const processSpecialValueInArray = value =>
isSymbol(value) || isFunction(value) || isUndefined(value) || isInfinity(value) || isNaN(value) ? null : value;
// Handling property values according to JSON specification
const processValue = value => {
if (isInfinity(value) || isNaN(value)) {
return null
}
if (isString(value)) {
return `"${value}"`
}
return value
};
// obj.loop = obj
const jsonStringify = (function () {
// Closure + WeakMap prevent circular references
let wp = new WeakMap();
//It is the function in the closure that recursively calls jsonstrify, not the jsonstrify function declared by const
return function jsonStringify(obj) {
if (wp.get(obj)) throw new TypeError('Converting circular structure to JSON');
let res = "";
if (isComplexDataType(obj)) {
if (obj.toJSON) return obj.toJSON;
if (!isValidObj(obj)) {
return
}
wp.set(obj, obj);
if (Array.isArray(obj)) {
res += "[";
let temp = [];
obj.forEach((value) => {
temp.push(
isComplexDataType(value) && !isFunction(value) ?
jsonStringify(value) :
`${processSpecialValueInArray(value, true)}`
)
});
res += `${temp.join(',')}]`
} else {
res += "{";
let temp = [];
Object.keys(obj).forEach((key) => {
if (isComplexDataType(obj[key])) {
if (isValidObj(obj[key])) {
temp.push(`"${key}":${jsonStringify(obj[key])}`)
} else if (isDate(obj[key])) {
temp.push(`"${key}":"${obj[key].toISOString()}"`)
} else if (!isFunction(obj[key])) {
temp.push(`"${key}":{}`)
}
} else if (isValidBasicDataType(obj[key])) {
temp.push(`"${key}":${processValue(obj[key])}`)
}
});
res += `${temp.join(',')}}`
}
} else if (isSymbol(obj)) {
return
} else {
return obj
}
return res
}
})();
// example
let s = Symbol('s')
let obj = {
str: "123",
arr: [1, {e: 1}, s, () => {
}, undefined,Infinity,NaN],
obj: {a: 1},
Infinity: -Infinity,
nan: NaN,
undef: undefined,
symbol: s,
date: new Date(),
reg: /123/g,
func: () => {
},
dom: document.querySelector('body'),
};
console.log(jsonStringify(obj));
console.log(JSON.stringify(obj));
例子:
總結以上就是我與你分享的14個JavaScript的函數,這些函數也是我們作為一名web前端開發人員必須要知道的,希望對你有用,如果覺得對你有幫助的話,請記得點贊我,關注我,并將它分享給你身邊做開發的朋友,也許能夠幫助到他。

相關推薦HOT
更多>>
json格式是什么意思
JSON(JavaScript Object Notation)是一種輕量級的數據交換格式,常用于前后端數據傳輸、配置文件和日志文件等場景中。JSON 采用鍵值對的方式來...詳情>>
2023-04-11 13:51:20
什么是mybatisplus?有什么特點
Mybatis-Plus(簡稱MP)是一個基于Mybatis的持久開源層框架,它在Mybatis的基礎上擴展了一些實用的功能,使開發更加簡單、快速。以下是Mybatis-Pl...詳情>>
2023-03-06 16:05:42
zookeeper集群配置怎樣操作
ZooKeeper是一個分布式應用程序協調服務,它使用一組服務器來提供高可用性和容錯性。要配置ZooKeeper集群,需要完成以下步驟:1.下載和安裝ZooK...詳情>>
2023-03-03 11:23:01
性能測試的指標是什么
性能測試是一種通過測量系統或應用程序的特定方面來評估其性能的測試方法。性能測試可以幫助發現性能瓶頸,優化應用程序或系統的性能,從而提高...詳情>>
2023-03-01 10:11:00