撩一下一些必要的js工具函數
不管是什么項目,總有一些基本的功能函數默默的躺在你的工具庫中,為你遮擋bug,提升性能,一起來復習下!
debounce
當監聽一些scroll,resize事件時,如果我們什么都不限制,srcoll事件在滾動過程中會一直觸發,極大的影響性能,這個時候,就需要節流函數debounce。debounce函數返回一個函數,在給定的時間間隔下,連續被調用將不會觸發。
/* 事件停止被觸發N秒后才會再次觸發回調 * @param {Function} func - 回調執行函數 * @param {String} wait - 觸發間隔 * @param {Boolean} 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);
};
};
// Usage
var myEfficientFn = debounce(function() {
// todo
}, 250);
window.addEventListener('resize', myEfficientFn);
poll
很多時候,我們需要了解某個函數的執行狀態,并根據狀態執行相應的處理。在沒有事件通知時,需要以一定的時間間隔輪詢執行狀態。
/* 輪詢條件函數,根據狀態執行相應回調 * @param {Function} fn- 條件函數 * @param {Function} callback - 成功回調 * @param {Function} errback - 失敗回調 * @param {int} timeout - 超時間隔 * @param {int} interval - 輪詢間隔 */
function poll(fn, callback, errback, timeout, interval) {
var endTime = Number(new Date()) + (timeout || 2000);
interval = interval || 100;
(function p() {
// If the condition is met, we're done!
if(fn()) {
callback();
}
// If the condition isn't met but the timeout hasn't elapsed, go again
else if (Number(new Date()) < endTime) {
setTimeout(p, interval);
}
// Didn't match and too much time, reject!
else {
errback(new Error('timed out for ' + fn + ': ' + arguments));
}
})();
}
// Usage: ensure element is visible
poll(
function() {
return document.getElementById('lightbox').offsetWidth > 0;
},
function() {
// Done, success callback
},
function() {
// Error, failure callback
}
);
once
實用的執行一次函數,不用多解釋。雖然很簡單的函數,但是防止重復加載或者初始化的習慣必須養成。
function once(fn, context) {
var result;
return function() {
if(fn) {
result = fn.apply(context || this, arguments);
fn = null;
}
return result;
};
}
// Usage
var canOnlyFireOnce = once(function() {
console.log('Fired!');
});
getAbsoluteUrl
從字符串變量中獲取絕對url路徑并沒有那么容易,URL構造函數必須提供必要的參數,getAbsoluteUrl函數可以單純的從字符串輸入中得到絕對路徑。
var getAbsoluteUrl = (function() {
var a;
return function(url) {
if(!a) a = document.createElement('a');
a.href = url;
return a.href;
};
})();
// Usage
getAbsoluteUrl('/shirlyzhang'); // "http://imweb.io/shirlyzhang"
isNative
當需要重寫某個函數時,必須先確定其是否是原生函數。
(function() {
var toString = Object.prototype.toString;
var fnToString = Function.prototype.toString;
// 構造函數,數組
var reHostCtor = /^\[object .+?Constructor\]$/;
var reNative = RegExp('^' +
// 強制轉換(Object-toString)為字符串
String(toString)
// 轉移特殊字符
.replace(/[.*+?^${}()|[\]\/\\]/g, '\\$&')
// 替換 `toString` 為 `.*?`, 保持模板通用
// 替換 `for ...` 等字符來支持添加了額外信息的環境
.replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
);
function isNative(value) {
var type = typeof value;
return type == 'function'
// 使用 `Function#toString` 來繞過value原生的 `toString` 方法,避免誤判
? reNative.test(fnToString.call(value))
// 回退到宿主對象檢查。因為某些環境中,會將類型數組當做DOM方法。
: (value && type == 'object' && reHostCtor.test(toString.call(value))) || false;
}
module.exports = isNative;
}());
// Usage
isNative(alert); // true
isNative(myCustomFunction); // false
insertRule
使用css選擇器來選取節點修改樣式不太高效,可以選擇用js新建一段css樣式規則插入。
var sheet = (function() {
var style = document.createElement('style');
// WebKit 兼容
style.appendChild(document.createTextNode(''));
document.head.appendChild(style);
return style.sheet;
})();
// Usage
sheet.insertRule("header { float: left; opacity: 0.8; }", 1);
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);
}
// Usage
matchesSelector(document.getElementById('myDiv'), 'div.someSelector[some-attribute=true]')
本文由用戶 asule216 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!