跳到主要内容
JavaScript 开发常用工具函数精选 | 极客日志
JavaScript 大前端 算法
JavaScript 开发常用工具函数精选 JavaScript 开发中常需处理类型判断、数据克隆、格式转换及环境兼容等问题。本文整理了一套实用的工具函数集合,涵盖原始数据类型检测、对象数组深度操作、字符串命名规范转换、浏览器 UA 识别以及常见 DOM 性能优化方案。同时包含部分原生 API 的 Polyfill 实现,帮助开发者在跨平台环境下保持代码的一致性与健壮性,提升开发效率。
dehua dong 发布于 2025/2/5 0 浏览JavaScript 开发常用工具函数精选
在实际项目中,我们常会遇到原生 API 覆盖不全、跨浏览器兼容性问题或重复性逻辑。整理一套经过验证的工具函数库,能显著提升开发效率与代码健壮性。以下分类整理了类型判断、对象数组操作、字符串处理、环境检测及 DOM 性能优化等核心工具。
类型判断
准确识别数据类型是编写健壮代码的基础。Object.prototype.toString.call 是最可靠的判断方式,优于 typeof。
function isStatic (value ) {
return (
typeof value === 'string' ||
typeof value === 'number' ||
typeof value === 'boolean' ||
typeof value === 'undefined' ||
value === null
)
}
function isPrimitive (value ) {
return isStatic (value) || typeof value === 'symbol'
}
function isObject (value ) {
let type = typeof value;
return value != null && (type == 'object' || type == 'function' );
}
function getRawType (value ) {
return Object .prototype .toString .call (value). ( , - )
}
( ) {
. . . (obj) ===
}
( ) {
. . . (arr) ===
}
. = . || isArray;
( ) {
. . . (value) ===
}
( ) {
. . . (value) ===
}
( ) {
. . . (value) ===
}
slice
8
1
function
isPlainObject
obj
return
Object
prototype
toString
call
'[object Object]'
function
isArray
arr
return
Object
prototype
toString
call
'[object Array]'
Array
isArray
Array
isArray
function
isRegExp
value
return
Object
prototype
toString
call
'[object RegExp]'
function
isDate
value
return
Object
prototype
toString
call
'[object Date]'
function
isFunction
value
return
Object
prototype
toString
call
'[object Function]'
对象与数组操作 处理数据转换、克隆和去重是日常高频需求。注意深拷贝的局限性及类数组的判断标准。
function extend (to, _from ) {
for (let key in _from) {
to[key] = _from[key];
}
return to
}
Object .assign = Object .assign || function ( ){
if (arguments .length === 0 ) throw new TypeError ('Cannot convert undefined or null to object' );
let target = arguments [0 ],
args = Array .prototype .slice .call (arguments , 1 ),
key
args.forEach (function (item ){
for (key in item){
item.hasOwnProperty (key) && ( target[key] = item[key] )
}
})
return target
}
let clone = JSON .parse (JSON .stringify (target))
function clone (value, deep ) {
if (isPrimitive (value)) {
return value
}
if (isArrayLike (value)) {
value = Array .prototype .slice .call (value)
return deep ? value.map (item => clone (item, deep)) : value
} else if (isPlainObject (value)) {
let target = {}, key;
for (key in value) {
value.hasOwnProperty (key) && (target[key] = deep ? clone (value[key], deep) : value[key])
}
return target
}
let type = getRawType (value)
switch (type) {
case 'Date' :
case 'RegExp' :
case 'Error' : value = new window [type](value); break ;
}
return value
}
function isLength (value ) {
return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= Number .MAX_SAFE_INTEGER ;
}
function isArrayLike (value ) {
return value != null && isLength (value.length ) && !isFunction (value);
}
function isEmpty (value ) {
if (value == null ) {
return true ;
}
if (isArrayLike (value)) {
return !value.length ;
} else if (isPlainObject (value)) {
for (let key in value) {
if (hasOwnProperty.call (value, key)) {
return false ;
}
}
return true ;
}
return false ;
}
function cached (fn ) {
let cache = Object .create (null );
return function cachedFn (str ) {
let hit = cache[str];
return hit || (cache[str] = fn (str))
}
}
function unique (arr ) {
if (!isArrayLike (arr)) {
return arr
}
let result = []
let objarr = []
let obj = Object .create (null )
arr.forEach (item => {
if (isStatic (item)) {
let key = item + '_' + getRawType (item);
if (!obj[key]) {
obj[key] = true
result.push (item)
}
} else {
if (objarr.indexOf (item) === -1 ) {
objarr.push (item)
result.push (item)
}
}
})
return result
}
window .Set = window .Set || (function ( ) {
function Set (arr ) {
this .items = arr ? unique (arr) : [];
this .size = this .items .length ;
}
Set .prototype = {
add : function (value ) {
if (!this .has (value)) {
this .items .push (value);
this .size ++;
}
return this ;
},
clear : function ( ) {
this .items = []
this .size = 0
},
delete : function (value ) {
return this .items .some ((v, i ) => {
if (v === value) {
this .items .splice (i, 1 )
return true
}
return false
})
},
has : function (value ) {
return this .items .some (v => v === value)
},
values : function ( ) {
return this .items
},
}
return Set ;
}());
function max (arr ) {
arr = arr.filter (item => !_isNaN (item))
return arr.length ? Math .max .apply (null , arr) : undefined
}
function min (arr ) {
arr = arr.filter (item => !_isNaN (item))
return arr.length ? Math .min .apply (null , arr) : undefined
}
function random (lower, upper ) {
lower = +lower || 0
upper = +upper || 0
return Math .random () * (upper - lower) + lower;
}
字符串与格式化 处理命名规范转换和时间格式化时,正则表达式配合记忆化缓存效果最佳。
let camelizeRE = /-(\w)/g ;
function camelize (str ) {
return str.replace (camelizeRE, function (_, c ) {
return c ? c.toUpperCase () : '' ;
})
}
let _camelize = cached (camelize)
let hyphenateRE = /\B([A-Z])/g ;
function hyphenate (str ) {
return str.replace (hyphenateRE, '-$1' ).toLowerCase ()
}
let _hyphenate = cached (hyphenate);
function capitalize (str ) {
return str.charAt (0 ).toUpperCase () + str.slice (1 )
}
let _capitalize = cached (capitalize)
function repeat (str, n ) {
let res = '' ;
while (n) {
if (n % 2 === 1 ) {
res += str;
}
if (n > 1 ) {
str += str;
}
n >>= 1 ;
}
return res
};
function dateFormater (formater, t ) {
let date = t ? new Date (t) : new Date (),
Y = date.getFullYear () + '' ,
M = date.getMonth () + 1 ,
D = date.getDate (),
H = date.getHours (),
m = date.getMinutes (),
s = date.getSeconds ();
return formater.replace (/YYYY|yyyy/g , Y)
.replace (/YY|yy/g , Y.substr (2 , 2 ))
.replace (/MM/g , (M < 10 ? '0' : '' ) + M)
.replace (/DD/g , (D < 10 ? '0' : '' ) + D)
.replace (/HH|hh/g , (H < 10 ? '0' : '' ) + H)
.replace (/mm/g , (m < 10 ? '0' : '' ) + m)
.replace (/ss/g , (s < 10 ? '0' : '' ) + s)
}
function dateStrForma (str, from , to ) {
str += ''
let Y = ''
if (~(Y = from .indexOf ('YYYY' ))) {
Y = str.substr (Y, 4 )
to = to.replace (/YYYY|yyyy/g , Y)
} else if (~(Y = from .indexOf ('YY' ))) {
Y = str.substr (Y, 2 )
to = to.replace (/YY|yy/g , Y)
}
let k, i
['M' , 'D' , 'H' , 'h' , 'm' , 's' ].forEach (s => {
i = from .indexOf (s + s)
k = ~i ? str.substr (i, 2 ) : ''
to = to.replace (s + s, k)
})
return to
}
环境与浏览器检测 针对不同运行环境和浏览器特性进行适配,是前端工程化的重要一环。
let inBrowser = typeof window !== 'undefined' ;
let inWeex = typeof WXEnvironment !== 'undefined' && !!WXEnvironment .platform ;
let weexPlatform = inWeex && WXEnvironment .platform .toLowerCase ();
let UA = inBrowser && window .navigator .userAgent .toLowerCase ();
let isIE = UA && /msie|trident/ .test (UA );
let isIE9 = UA && UA .indexOf ('msie 9.0' ) > 0 ;
let isEdge = UA && UA .indexOf ('edge/' ) > 0 ;
let isAndroid = (UA && UA .indexOf ('android' ) > 0 ) || (weexPlatform === 'android' );
let isIOS = (UA && /iphone|ipad|ipod|ios/ .test (UA )) || (weexPlatform === 'ios' );
let isChrome = UA && /chrome/ \d+/.test (UA ) && !isEdge;
function getExplorerInfo ( ) {
let t = navigator.userAgent .toLowerCase ();
return 0 <= t.indexOf ("msie" ) ? {
type : "IE" ,
version : Number (t.match (/msie ([\d]+)/ )[1 ])
} : !!t.match (/trident/ .+?rv :(([\d.]+))/) ? {
type : "IE" ,
version : 11
} : 0 <= t.indexOf ("edge" ) ? {
type : "Edge" ,
version : Number (t.match (/edge\/([\d]+)/ )[1 ])
} : 0 <= t.indexOf ("firefox" ) ? {
type : "Firefox" ,
version : Number (t.match (/firefox\/([\d]+)/ )[1 ])
} : 0 <= t.indexOf ("chrome" ) ? {
type : "Chrome" ,
version : Number (t.match (/chrome\/([\d]+)/ )[1 ])
} : 0 <= t.indexOf ("opera" ) ? {
type : "Opera" ,
version : Number (t.match (/opera.([\d]+)/ )[1 ])
} : 0 <= t.indexOf ("Safari" ) ? {
type : "Safari" ,
version : Number (t.match (/version\/([\d]+)/ )[1 ])
} : {
type : t,
version : -1
}
}
function isPCBroswer ( ) {
let e = navigator.userAgent .toLowerCase ()
, t = "ipad" == e.match (/ipad/i )
, i = "iphone" == e.match (/iphone/i )
, r = "midp" == e.match (/midp/i )
, n = "rv:1.2.3.4" == e.match (/rv:1.2.3.4/i )
, a = "ucweb" == e.match (/ucweb/i )
, o = "android" == e.match (/android/i )
, s = "windows ce" == e.match (/windows ce/i )
, l = "windows mobile" == e.match (/windows mobile/i );
return !(t || i || r || n || a || o || s || l)
}
function isNative (value ) {
return typeof value === 'function' && /[native code]/ .test (value.toString ())
}
DOM 与性能优化
function GetUrlParam ( ) {
let url = document .location .toString ();
let arrObj = url.split ("?" );
let params = Object .create (null )
if (arrObj.length > 1 ) {
arrObj = arrObj[1 ].split ("&" );
arrObj.forEach (item => {
item = item.split ("=" );
params[item[0 ]] = item[1 ] || ''
})
}
return params;
}
function downloadFile (filename, data ) {
let DownloadLink = document .createElement ('a' );
if (DownloadLink ) {
document .body .appendChild (DownloadLink );
DownloadLink .style = 'display: none' ;
DownloadLink .download = filename;
DownloadLink .href = data;
if (document .createEvent ) {
let DownloadEvt = document .createEvent ('MouseEvents' );
DownloadEvt .initEvent ('click' , true , false );
DownloadLink .dispatchEvent (DownloadEvt );
} else if (document .createEventObject ) {
DownloadLink .fireEvent ('onclick' );
} else if (typeof DownloadLink .onclick == 'function' ) {
DownloadLink .onclick ();
}
document .body .removeChild (DownloadLink );
}
}
function toFullScreen ( ) {
let el = document .documentElement ;
let rfs = el.requestFullScreen || el.webkitRequestFullScreen || el.mozRequestFullScreen || el.msRequestFullScreen ;
if (rfs) {
rfs.call (el);
} else if (typeof window .ActiveXObject !== "undefined" ) {
let wscript = new ActiveXObject ("WScript.Shell" );
if (wscript != null ) {
wscript.SendKeys ("{F11}" );
}
} else {
alert ("浏览器不支持全屏" );
}
}
function exitFullscreen ( ) {
let el = document .documentElement ;
let cfs = el.cancelFullScreen || el.webkitCancelFullScreen || el.mozCancelFullScreen || el.exitFullScreen ;
if (cfs) {
cfs.call (el);
} else if (typeof window .ActiveXObject !== "undefined" ) {
let wscript = new ActiveXObject ("WScript.Shell" );
if (wscript != null ) {
wscript.SendKeys ("{F11}" );
}
} else {
alert ("切换失败,可尝试 Esc 退出" );
}
}
window .requestAnimationFrame = window .requestAnimationFrame ||
window .webkitRequestAnimationFrame ||
window .mozRequestAnimationFrame ||
window .msRequestAnimationFrame ||
window .oRequestAnimationFrame ||
function (callback ) {
window .setTimeout (callback, 1000 / 60 );
};
window .cancelAnimationFrame = window .cancelAnimationFrame ||
window .webkitCancelAnimationFrame ||
window .mozCancelAnimationFrame ||
window .msCancelAnimationFrame ||
window .oCancelAnimationFrame ||
function (id ) {
window .clearTimeout (id);
}
window .onload = function ( ) {
setTimeout (function ( ) {
let t = performance.timing
console .log ('DNS 查询耗时:' + (t.domainLookupEnd - t.domainLookupStart ).toFixed (0 ))
console .log ('TCP 链接耗时:' + (t.connectEnd - t.connectStart ).toFixed (0 ))
console .log ('request 请求耗时:' + (t.responseEnd - t.responseStart ).toFixed (0 ))
console .log ('解析 dom 树耗时:' + (t.domComplete - t.domInteractive ).toFixed (0 ))
console .log ('白屏时间:' + (t.responseStart - t.navigationStart ).toFixed (0 ))
console .log ('domready 时间:' + (t.domContentLoadedEventEnd - t.navigationStart ).toFixed (0 ))
console .log ('onload 时间:' + (t.loadEventEnd - t.navigationStart ).toFixed (0 ))
if (performance.memory ) {
console .log ('js 内存使用占比:' + (performance.memory .usedJSHeapSize / performance.memory .totalJSHeapSize * 100 ).toFixed (2 ) + '%' )
}
})
}
document .addEventListener ('keydown' , function (event ) {
return !(
112 == event.keyCode ||
123 == event.keyCode ||
event.ctrlKey && 82 == event.keyCode ||
event.ctrlKey && 78 == event.keyCode ||
event.shiftKey && 121 == event.keyCode ||
event.altKey && 115 == event.keyCode ||
"A" == event.target .tagName && event.shiftKey
) || (event.returnValue = false )
});
['contextmenu' , 'selectstart' , 'copy' ].forEach (function (ev ) {
document .addEventListener (ev, function (event ) {
return event.returnValue = false
});
});
原生方法补全 为了兼容旧环境,部分常用 API 提供了 Polyfill 实现。
function _isNaN (v ) {
return !(typeof v === 'string' || typeof v === 'number' ) || isNaN (v)
}
Object .keys = Object .keys || function keys (object ) {
if (object === null || object === undefined ) {
throw new TypeError ('Cannot convert undefined or null to object' );
}
let result = []
if (isArrayLike (object) || isPlainObject (object)) {
for (let key in object) {
object.hasOwnProperty (key) && (result.push (key))
}
}
return result
}
Object .values = Object .values || function values (object ) {
if (object === null || object === undefined ) {
throw new TypeError ('Cannot convert undefined or null to object' );
}
let result = []
if (isArrayLike (object) || isPlainObject (object)) {
for (let key in object) {
object.hasOwnProperty (key) && (result.push (object[key]))
}
}
return result
}
Array .prototype .fill = Array .prototype .fill || function fill (value, start, end ) {
let ctx = this
let length = ctx.length ;
start = parseInt (start)
if (isNaN (start)) {
start = 0
} else if (start < 0 ) {
start = -start > length ? 0 : (length + start);
}
end = parseInt (end)
if (isNaN (end) || end > length) {
end = length
} else if (end < 0 ) {
end += length;
}
while (start < end) {
ctx[start++] = value;
}
return ctx;
}
Array .prototype .includes = Array .prototype .includes || function includes (value, start ) {
let ctx = this
let length = ctx.length ;
start = parseInt (start)
if (isNaN (start)) {
start = 0
} else if (start < 0 ) {
start = -start > length ? 0 : (length + start);
}
let index = ctx.indexOf (value)
return index >= start;
}
Array .prototype .find = Array .prototype .find || function find (fn, ctx ) {
fn = fn.bind (ctx)
let result;
this .some ((value, index, arr ) => {
return fn (value, index, arr) ? (result = value, true ) : false
})
return result
}
Array .prototype .findIndex = Array .prototype .findIndex || function findIndex (fn, ctx ) {
fn = fn.bind (ctx)
let result;
this .some ((value, index, arr ) => {
return fn (value, index, arr) ? (result = index, true ) : false
})
return result
}
function getPropByPath (obj, path, strict ) {
let tempObj = obj;
path = path.replace (/\[(\w+)\]/g , '.$1' );
path = path.replace (/^\./ , '' );
let keyArr = path.split ('.' );
let i = 0 ;
for (let len = keyArr.length ; i < len - 1 ; ++i) {
if (!tempObj && !strict) break ;
let key = keyArr[i];
if (key in tempObj) {
tempObj = tempObj[key];
} else {
if (strict) {
throw new Error ('please transfer a valid prop path to form item!' );
}
break ;
}
}
return {
o : tempObj,
k : keyArr[i],
v : tempObj ? tempObj[keyArr[i]] : null
};
}
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online