你需要知道的 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 前端开发人员必须要知道的,希望对你有用,如果觉得对你有帮助的话,请记得点赞我,关注我,并将它分享给你身边做开发的朋友,也许能够帮助到他。
你需要知道的 14 个常用的 JavaScript 函数的更多相关文章
- Linux 用户必须知道的 14 个常用 Linux 终端快捷键
简介:以下是一些每个 Linux 用户必须使用的键盘快捷键. 使用命令行时,这些 Linux 快捷键将提升你的工作效率和效率. 你知道什么把专业用户和普通用户分开的吗?掌握键盘快捷键. 好的!这虽不是 ...
- [技术翻译]您应该知道的13个有用的JavaScript数组技巧
本次预计翻译三篇文章如下: 01.[译]9个可以让你在2020年成为前端专家的项目 02.[译]预加载响应式图像,从Chrome 73开始实现 03.[译]您应该知道的13个有用的JavaScript ...
- 很少有人知道的c++中的try块函数
c++有一些在现实世界中很少看到的结构.这些结构有着自己的用法,但是要特别小心保守的予以运用.就像是网站 The Old New Thing首页标题上面的说的那样: “代码通常被读的次数原因超过了被写 ...
- 对于JavaScript的函数.NET开发人员应该知道的11件事
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 昨天小感冒今天重感冒,也不能长篇大论.如果你是.NET开发人员,在进入前端开发领域的时候,对 ...
- 收集JavaScript中常用的方法函数
本文中,收集了一些比较常用的Javascript函数,希望对学习JS的朋友们有所帮助. 1. 字符串长度截取 function cutstr(str, len) { var temp, icount ...
- 不得不看,只有专家才知道的17个SQL查询提速秘诀!
不得不看,只有专家才知道的17个SQL查询提速秘诀! 原创 2018-01-23 布加迪编译 51CTO技术栈 “ 除非你遵循本文介绍的这些技巧,否则很容易编写出减慢查询速度或锁死数据库的数据库代码. ...
- 一定要知道的,那些Linux操作命令
一定要知道的,那些Linux基本操作命令(一) 目录 1.文件和目录操作命令 2.用户和用户组操作命令 3.vim编辑器操作命令 4.打包和解压操作命令 5.系统操作命令 为什么要学习linux? 1 ...
- PHP程序员应该知道的15个库
最几年,PHP已经成为最受欢迎的一种有效服务器端编程语言.据2013年发布的一份调查报告显示,PHP语言已经被安装在全球超过2.4亿个网站以及210万台Web服务器之上.PHP代表超文本预处理器,它主 ...
- Android 程序员必须知道的 53 个知识点
1. android 单实例运行方法 我们都知道 Android 平台没有任务管理器,而内部 App 维护者一个 Activity history stack 来实现窗口显示和销毁,对于常规从快捷方式 ...
- 理工科应该的知道的C/C++数学计算库(转)
理工科应该的知道的C/C++数学计算库(转) 作为理工科学生,想必有限元分析.数值计算.三维建模.信号处理.性能分析.仿真分析...这些或多或少与我们常用的软件息息相关,假如有一天你只需要这些大型软件 ...
随机推荐
- ubuntu ssh远程访问出现Permission denied(publickey,password)解决方法
windows上安装SSH服务设置–>应用–>可选功能–>添加功能–>安装 OpenSSH服务器 和 OpenSSH客户端在左下角搜索栏输入服务,将相关SSH服务设置为自动(延 ...
- css3 旋转 八仙桌
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- python机器学习——逻辑回归方法
背景与原理: 线性回归可以实现对连续结果的预测,但是现实生活中我们常见的另一种问题是分类问题,尤其是二分类问题,在这种情况下使用线性回归就不太合适了,我们实际上需要计算出的是一个在$[0,1]$之间的 ...
- ElasticSeach性能调优
1. 硬件相关 1.1 硬盘 一块好的硬盘,会带来ES整体性能10倍以上提升,推荐在datanode节点上使用SSD硬盘,索引的data目录,存放在SSD硬盘上. 1.2 内存 建议内存>128 ...
- 出现SocketTimeoutException后一直无法在连接服务器
在做接入sdk功能的时候,经常出现一个问题,内网向外网服务器建立连接并发送数据经常会报SocketTimeoutException这个错误,且一旦出现便大几率再也连不上了.修改之前的代码为: publ ...
- C#——》发布ASP.NET Core项目到Windows IIS服务器中环境部署
服务器:Windows Server2012 R2 IIS:8 .net Core版本:1.1.2 一,在VS中点击项目-->依赖项-->SDK下可以查看当前项目.Net core是哪个版 ...
- binlog2sql 实战心得
原创:binlog2sql在GitHub的地址:https://github.com/danfengcao/binlog2sql 作者:danfengcao 功能:从MySQL binlog解析出你要 ...
- 认识flutter
flutter是谷歌的移动的ui框架,可以快速的在ios和安卓上构建高质量的原生用户界面.最主要的是完全免费开源.开发快,最重要的是使用flutter开发的开发工作者也越来越多了,生态圈也越来越好了. ...
- python 循环 类型转换
- 05 HDFS Java API应用实例
一.在Ubuntu系统中安装和配置Eclipse 二.利用hadoop 的java api,向HDFS写一个文件. 三.从HDFS读取一个文件的内容.