当前位置:网站首页>分享 14 个你必须知道的 JS 函数
分享 14 个你必须知道的 JS 函数
2022-08-03 17:28:00 【前端达人】

英文 | https://javascript.plainenglish.io/you-must-understand-these-14-javasript-functions-1f4fa1c620e2
翻译 | 杨小爱
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前端开发人员必须要知道的,希望对你有用,如果觉得对你有帮助的话,请记得点赞我,关注我,并将它分享给你身边做开发的朋友,也许能够帮助到他。
学习更多技能
请点击下方公众号
![]()
边栏推荐
- 微信小程序 - 数组 push / unshift 追加后数组返回内容为数字(数组添加后打印结果为 Number 数值类型)
- DataWorks 标准版怎样实现SQL代码的复用?
- sibling component communication context
- A complete detailed tutorial on building intranet penetration ngrok (with pictures and truth)
- 关于 Intel 在 micro-vm 快速启动的探索及实例演示 | 第 36-38 期
- J9数字虚拟论:元宇宙的潜力:一股推动社会进步的力量
- Web3 安全风险令人生畏?应该如何应对?
- SwinIR combat: record the training process of SwinIR in detail
- 华为ECS云服务器上安装Docker及部署Redis详细教程【华为云至简致远】
- LyScript 内存交换与差异对比
猜你喜欢

TiKV & TiFlash 加速复杂业务查询丨TiFlash 应用实践

TiKV & TiFlash accelerate complex business queries丨TiFlash application practice

C# 构造函数如人之影子

一些嵌入式软件设计经验

security加密解密

数字资产的价值激发:NFT 质押

深度学习跟踪DLT (deep learning tracker)

融云「音视频架构实践」技术专场【内含完整PPT】

大型企业数据治理的现状和解决方案有哪些参考?_光点科技

After using Stream for many years, does collect still have these "saucy operations"?
随机推荐
Interpretation of the paper (JKnet) "Representation Learning on Graphs with Jumping Knowledge Networks"
Detailed explanation of setting HiSilicon MMZ memory and OS memory
405. Convert a Number to Hexadecimal
大型企业数据治理的现状和解决方案有哪些参考?_光点科技
【技术白皮书】第一章:OCR智能文字识别新发展——深度学习的文本信息抽取
【数仓】数据质量监控
软件盘点企业使用服装ERP的好处
论文解读(JKnet)《Representation Learning on Graphs with Jumping Knowledge Networks》
security加密解密
How ArkUI adapter somehow the screen
【Metaverse系列一】元宇宙的奥秘
Halcon 小笔记 C# 图片是否有效
CC2530_ZigBee+华为云IOT:设计一套属于自己的冷链采集系统
CC2530_ZigBee+HUAWEI CLOUD IOT: Design your own cold chain acquisition system
JS中对象数组用sort按属性排序
关于oracle表空间在线碎片整理
TypeScript文件的编译执行
新“妖股”13个交易日暴涨320倍,市值3100亿美元超阿里
TypeScript的配置文件tsconfig.json
腾讯电竞的蓝翔梦