JavaScript 开发者必备的 7 个实用函数
本文汇总了 JavaScript 开发中常用的 7 个基础函数,包括防抖(debounce)、轮询(poll)、单次执行(once)、绝对 URL 获取、原生函数检测、动态样式插入及元素匹配选择器。掌握这些函数能有效提升代码性能并简化常见开发任务。
JavaScript 基础函数概述
回顾早期的 JavaScript 开发,实现各种功能往往依赖于一些基础函数。由于不同浏览器厂商在功能实现上存在差异,不仅边缘功能如此,基础功能如 addEventListener 和 attachEvent 也面临兼容性问题。尽管浏览器环境已大幅改善,但仍有部分函数是每位开发者必须掌握的,它们能帮助完成特定功能并显著提升代码性能。
debounce:高频事件防抖处理
debounce(防抖)
针对高资源消耗的事件处理,debounce 函数提供了一种高效的解决方案。如果不对 scroll、resize 或 key* 等高频触发事件使用防抖处理,极易导致性能问题。以下代码展示了如何实现一个保持代码高效运行的 debounce 函数:
// 返回一个函数,如果它被不间断地调用,它将不会得到执行。该函数在停止调用 N 毫秒后,再次调用它才会得到执行。如果有传递 ‘immediate' 参数,会马上将函数安排到执行队列中,而不会延迟。
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
// 用法
var myEfficientFn = debounce(function() {
// 所有繁重的操作
}, 250);
window.addEventListener('resize', myEfficientFn);
debounce 函数的核心机制是限制回调函数在指定时间间隔内只能执行一次。当为高频触发的事件绑定回调时,这一机制尤为重要,它能有效避免不必要的重复计算和资源浪费。
poll:状态轮询检测机制
poll(轮询)
虽然前文提到了 debounce,但在某些场景下,如果无法通过事件监听来判断状态,就需要采用轮询机制,即每隔一段时间检查状态是否满足预期要求。
function poll(fn, callback, errback, timeout, interval) {
var endTime = Number(new Date()) + (timeout || 2000);
interval = interval || 100;
(function p() {
// 如果条件满足,则执行!
if(fn()) {
callback();
}
// 如果条件不满足,但并未超时,再来一次
else if (Number(new Date()) < endTime) {
setTimeout(p, interval);
}
// 不匹配且时间消耗过长,则拒绝!
else {
errback(new Error('timed out for ' + fn + ': ' + arguments));
}
})();
}
// 用法:确保元素可见
poll(
function() {
return document.getElementById('lightbox').offsetWidth > 0;
},
function() {
// 执行,成功的回调函数
},
function() {
// 错误,失败的回调函数
}
);
轮询技术在 Web 开发中应用已久,并且在未来很长一段时间内仍将是解决特定状态检测问题的有效手段。
once:确保功能单次执行
once(单次执行)
有时我们需要确保某个功能仅执行一次,其效果类似于 onload 事件。以下代码实现了这一功能:
function once(fn, context) {
var result;
return function() {
if(fn) {
result = fn.apply(context || this, arguments);
fn = null;
}
return result;
};
}
// 用法
var canOnlyFireOnce = once(function() {
console.log('Fired!');
});
canOnlyFireOnce();
// "Fired!"
canOnlyFireOnce();
// nada
// 没有执行指定函数
once 函数通过确保给定函数只能被调用一次,有效防止了重复初始化带来的潜在问题。
getAbsoluteUrl:优雅获取绝对 URL
getAbsoluteUrl(获取绝对 URL)
从字符串变量解析出绝对 URL 并非想象中那么简单。某些 URL 构造器若缺少必要参数会引发错误,而有时开发者并不清楚具体需要提供哪些参数。下面介绍一种优雅的技巧,只需传入一个字符串即可获取对应的绝对 URL。
var getAbsoluteUrl = (function() {
var a;
return function(url) {
if(!a) a = document.createElement('a');
a.href = url;
return a.href;
};
})();
// 用法
getAbsoluteUrl('/something');
// http://davidwalsh.name/something
利用 a 元素的 href 属性处理 URL 看似简单,但 return 语句返回的是一个经过浏览器解析后可靠的绝对 URL,解决了相对路径转换的问题。
isNative:检测原生函数
isNative(检测原生函数)
若需判断某个指定函数是否为浏览器原生实现,或者能否通过声明覆盖它,可以使用以下便捷代码来获取答案:
;(function() {
// 用于处理传入参数 value 的内部 `[[Class]]`
var toString = Object.prototype.toString;
// 用于解析函数的反编译代码
var fnToString = Function.prototype.toString;
// 用于检测宿主构造器 (Safari > 4 ;真的输出特定的数组)
var reHostCtor = /^[object .+?Constructor]$/;
// 用一个标准的原生方法作为模板,编译一个正则表达式。
// 我们选择 'Object#toString' 因为它一般不会被污染。
var reNative = RegExp('^' +
// 将 'Object#toString' 强制转为字符串
String(toString)
// 转义所有指定的正则表达式字符
.replace(/[.*+?^${}()|[]/]/g, '$&')
// 用 '.*?' 替换提及的 'toString' ,以保持模板的通用性。
// 将 'for ...' 之类的字符替换掉,以兼容 Rhino 等环境,因为这些环境添加了额外的信息,如方法参数数量。
.replace(/toString|(function).*?(?=()| for .+?(?=])/g, '$1.*?') + '$'
);
function isNative(value) {
var type = typeof value;
return type == 'function'
// 用 'Function#toString' (fnToString)绕过了值(value)本身的 'toString' 方法,以免被伪造所欺骗。
? reNative.test(fnToString.call(value))
// 回退到宿主对象的检查,因为某些环境(浏览器)将类型数组(typed arrays)之类的东西当作 DOM 方法,此时可能不遵循标准的原生正则表达式。
: (value && type == 'object' && reHostCtor.test(toString.call(value))) || false;
}
// 导出函数
module.exports = isNative;
}());
// 用法
isNative(alert);
// true
isNative(myCustomFunction);
// false
尽管该函数并非完美无缺,但它能准确完成任务,帮助开发者区分原生方法与自定义方法。
insertRule:动态插入样式规则
insertRule(插入样式规则)
我们通常通过 document.querySelectorAll 获取 NodeList 并为每个元素单独设置样式,但存在更高效的方法:直接通过样式表插入规则。例如,你可以直接在样式表中完成样式的定义:
var sheet = (function() {
// 创建 <style> 标签
var style = document.createElement('style');
// 如果你需要指定媒介类型,则可以在此添加一个 media (和/或 media query)
// style.setAttribute('media', 'screen')
// style.setAttribute('media', 'only screen and (max-width : 1024px)')
// WebKit hack :(
style.appendChild(document.createTextNode(''));
// 将 <style> 元素添加到页面
document.head.appendChild(style);
return style.sheet;
})();
// 用法
sheet.insertRule("header { float: left; opacity: 0.8; }", 1);
这种方法对于动态且重度依赖 AJAX 的网站尤为有用。通过为选择器直接设置样式规则,无需为每个匹配到的元素单独设置样式,无论是当前还是未来的元素都能自动应用该样式。
matchesSelector:元素匹配校验
matchesSelector(元素匹配选择器) 在进行后续操作前,我们常需进行输入校验以确保数据可靠或表单有效。那么如何确保一个元素具备执行后续操作的资格?若元素匹配给定的选择器,可使用 matchesSelector 函数进行校验:
function matchesSelector(el, selector) {
var p = Element.prototype;
var f = p.matches || p.webkitMatchesSelector || p.mozMatchesSelector || p.msMatchesSelector || function(s) {
return [].indexOf.call(document.querySelectorAll(s), this) !== -1;
};
return f.call(el, selector);
}
// 用法
matchesSelector(document.getElementById('myDiv'), 'div.someSelector[some-attribute=true]')
以上介绍了 7 个 JavaScript 函数,它们是每位开发者都应牢记的基础工具。如果你还有其他推荐的函数,欢迎分享!
以上内容即为本文的全部介绍,希望读者们能从中受益。
D3.js 比例尺与坐标轴的配置详解
2026-11-05 16:54:46
JavaScript怎么遍历对象的Symbol键和不可枚举属性
2026-11-05 13:13:39
封装一个健壮的JS字符串判空工具函数
2026-11-05 12:16:14
JavaScript合并数组的三种常用方法:concat、扩展运算符与push
2026-11-05 11:22:29
JavaScript立即执行函数(IIFE)是什么及基本语法
2026-11-05 10:51:19
