1、对象深拷贝
function deepClone(obj) {
const _toString = Object.prototype.toString
// null, undefined, non-object, function
if (!obj || typeof obj !== 'object') {
return obj
}
// DOM Node
if (obj.nodeType && 'cloneNode' in obj) {
return obj.cloneNode(true)
}
// Date
if (_toString.call(obj) === '[object Date]') {
return new Date(obj.getTime())
}
// RegExp
if (_toString.call(obj) === '[object RegExp]') {
const flags = []
if (obj.global) { flags.push('g') }
if (obj.multiline) { flags.push('m') }
if (obj.ignoreCase) { flags.push('i') }
return new RegExp(obj.source, flags.join(''))
}
const result = Array.isArray(obj) ? [] : obj.constructor ? new obj.constructor() : {}
for (const key in obj) {
result[key] = deepClone(obj[key])
}
return result
}
2、wind-dom 插件源码中的 hasClass
、 addClass
、removeClass
多看看人家写的源码,精简优美,涨姿势。
var trim = function (string) {
return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, '');
};
var hasClass = function (el, cls) {
if (!el || !cls) return false;
if (cls.indexOf(' ') != -1) throw new Error('className should not contain space.');
if (el.classList) {
return el.classList.contains(cls);
} else {
return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1;
}
};
var addClass = function (el, cls) {
if (!el) return;
var curClass = el.className;
var classes = (cls || '').split(' ');
for (var i = 0, j = classes.length; i < j; i++) {
var clsName = classes[i];
if (!clsName) continue;
if (el.classList) {
el.classList.add(clsName);
} else {
if (!hasClass(el, clsName)) {
curClass += ' ' + clsName;
}
}
}
if (!el.classList) {
el.className = curClass;
}
};
var removeClass = function (el, cls) {
if (!el || !cls) return;
var classes = cls.split(' ');
var curClass = ' ' + el.className + ' ';
for (var i = 0, j = classes.length; i < j; i++) {
var clsName = classes[i];
if (!clsName) continue;
if (el.classList) {
el.classList.remove(clsName);
} else {
if (hasClass(el, clsName)) {
curClass = curClass.replace(' ' + clsName + ' ', ' ');
}
}
}
if (!el.classList) {
el.className = trim(curClass);
}
};
3、判断一个变量是否为空数组
var arr = [];
// Array.isArray是ES5提供的,如果不支持。用下面的方案重写Array.isArray()方法,这种操作是叫重写吧?
if (!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
if(Array.isArray(arr) && arr.length === 0){
console.log('是空数组');
}
4、实现一个函数clone,可以对JavaScript中的5种主要的数据类型(包括Number、String、Object、Array、Boolean)进行值复制。
/**
* 对象克隆
* 支持基本数据类型及对象
* 递归方法
*/
function clone(obj) {
var o;
switch (typeof obj) {
case "undefined":
break;
case "string":
o = obj + "";
break;
case "number":
o = obj - 0;
break;
case "boolean":
o = obj;
break;
case "object": // object 分为两种情况 对象(Object)或数组(Array)
if (obj === null) {
o = null;
} else {
if (Object.prototype.toString.call(obj).slice(8, -1) === "Array") {
o = [];
for (var i = 0; i obj.length; i++) {
o.push(clone(obj[i]));
}
} else {
o = {};
for (var k in obj) {
o[k] = clone(obj[k]);
}
}
}
break;
default:
o = obj;
break;
}
return o;
}
5、统计字符串”aaaabbbccccddfgh”中字母个数或统计最多字母数。
var str = "aaaabbbccccddfgh";
var obj = {};
for(var i=0;istr.length;i++){
var v = str.charAt(i);
if(obj[v] & obj[v].value == v){
obj[v].count = ++ obj[v].count;
}else{
obj[v] = {};
obj[v].count = 1;
obj[v].value = v;
}
}
for(key in obj){
document.write(obj[key].value +'='+obj[key].count+' ');
// a=4 b=3 c=4 d=2 f=1 g=1 h=1
}
6、写一个function,清除字符串前后的空格。(兼容所有浏览器)
function trim(str) {
if (str & typeof str === "string") {
return str.replace(/(^s*)|(s*)$/g,""); //去除前后空白符
}
}
7、二维数组转成一维数组
let data = [
{
id: '1',
label: '1',
sort: 1,
children:[
{ pid: null, label: '1-1', sort: null },
{ pid: null, label: '1-2', sort: null },]
},{
id: '2',
label: '2',
sort: 2,
children:[
{ pid: null, label: '2-1', sort: null },
{ pid: null, label: '2-2', sort: null },]
}]
let b = data.flatMap(i=>{
i.children.map((j,index)=>{
j.pid = i.id;
j.sort = index
});
let a = i.children;
delete i.children;
a.unshift(i);
console.log(a);
return a
});
console.log(b);
8、获取url参数
//1
function getParams(url) {
const res = {}
if (url.includes('?')) {
const str = url.split('?')[1]
const arr = str.split('&')
arr.forEach(item => {
const key = item.split('=')[0]
const val = item.split('=')[1]
res[key] = decodeURIComponent(val) // 解码
})
}
return res
}
// 测试
const user = getParams('http://www.baidu.com?user=%E9%98%BF%E9%A3%9E&age=16')
console.log(user) // { user: '阿飞', age: '16' }
//2
// 创建一个URLSearchParams实例
const urlSearchParams = new URLSearchParams(window.location.search);
// 把键值对列表转换为一个对象
const params = Object.fromEntries(urlSearchParams.entries());
9、判断设备类型
// 判断手机 or 电脑
if ((navigator.userAgent.match(/(iPhone|iPod|Android|ios|iOS|iPad|Backerry|WebOS|Symbian|Windows Phone|Phone)/i))) {
console.log("手机访问.")
} else {
console.log("电脑访问.")
}
10、判断浏览器类型
var Sys = {};
var ua = navigator.userAgent.toLowerCase();
var s;
(s = ua.match(/msie ([\d.]+)/))
? (Sys.ie = s[1])
: (s = ua.match(/firefox\/([\d.]+)/))
? (Sys.firefox = s[1])
: (s = ua.match(/chrome\/([\d.]+)/))
? (Sys.chrome = s[1])
: (s = ua.match(/opera.([\d.]+)/))
? (Sys.opera = s[1])
: (s = ua.match(/version\/([\d.]+).*safari/))
? (Sys.safari = s[1])
: 0;
if (Sys.ie) console.log('IE: ' + Sys.ie);
if (Sys.firefox) console.log('Firefox: ' + Sys.firefox);
if (Sys.chrome) console.log('Chrome: ' + Sys.chrome);
if (Sys.opera) console.log('Opera: ' + Sys.opera);
if (Sys.safari) console.log('Safari: ' + Sys.safari);
11、保留两位小数
// js保留两位小数方法总结
var num = 2.446242342;
num = num.toFixed(2); // 输出结果为 2.45
Math.floor(15.7784514000 * 100) / 100 // 输出结果为 15.77
Number(15.7784514000.toString().match(/^\d+(?:\.\d{0,2})?/)) // 输出结果为 15.77,不能用于整数如 10 必须写为10.0000
//四舍五入保留2位小数(若第二位小数为0,则保留一位小数)
function keepTwoDecimal(num) {
var result = parseFloat(num);
if (isNaN(result)) {
alert('传递参数错误,请检查!');
return false;
}
result = Math.round(num * 100) / 100;
return result;
}
//四舍五入保留2位小数(不够位数,则用0替补)
function keepTwoDecimalFull(num) {
var result = parseFloat(num);
if (isNaN(result)) {
alert('传递参数错误,请检查!');
return false;
}
result = Math.round(num * 100) / 100;
var s_x = result.toString();
var pos_decimal = s_x.indexOf('.');
if (pos_decimal < 0) {
pos_decimal = s_x.length;
s_x += '.';
}
while (s_x.length <= pos_decimal + 2) {
s_x += '0';
}
return s_x;
}
//保留两位小数
//功能:将浮点数四舍五入,取小数点后2位
function toDecimal(x) {
var f = parseFloat(x);
if (isNaN(f)) {
return;
}
f = Math.round(x * 100) / 100;
return f;
}
//制保留2位小数,如:2,会在2后面补上00.即2.00
function toDecimal2(x) {
var f = parseFloat(x);
if (isNaN(f)) {
return false;
}
var f = Math.round(x * 100) / 100;
var s = f.toString();
var rs = s.indexOf('.');
if (rs < 0) {
rs = s.length;
s += '.';
}
while (s.length <= rs + 2) {
s += '0';
}
return s;
}
function fomatFloat(src, pos) {
return Math.round(src * Math.pow(10, pos)) / Math.pow(10, pos);
}
//四舍五入
alert("保留2位小数:" + toDecimal(3.14159267));
alert("强制保留2位小数:" + toDecimal2(3.14159267));
alert("保留2位小数:" + toDecimal(3.14559267));
alert("强制保留2位小数:" + toDecimal2(3.15159267));
alert("保留2位小数:" + fomatFloat(3.14559267, 2));
alert("保留1位小数:" + fomatFloat(3.15159267, 1));
//五舍六入
alert("保留2位小数:" + 1000.003.toFixed(2));
alert("保留1位小数:" + 1000.08.toFixed(1));
alert("保留1位小数:" + 1000.04.toFixed(1));
alert("保留1位小数:" + 1000.05.toFixed(1));
//科学计数
alert(3.1415.toExponential(2));
alert(3.1455.toExponential(2));
alert(3.1445.toExponential(2));
alert(3.1465.toExponential(2));
alert(3.1665.toExponential(1));
//精确到n位,不含n位
alert("精确到小数点第2位" + 3.1415.toPrecision(2));
alert("精确到小数点第3位" + 3.1465.toPrecision(3));
alert("精确到小数点第2位" + 3.1415.toPrecision(2));
alert("精确到小数点第2位" + 3.1455.toPrecision(2));
alert("精确到小数点第5位" + 3.141592679287.toPrecision(5));
12、js封装获取DOM对象的方法
//取对象的封装
function $(eleStr) {
//为了区分,不同的取对象方式,以加前缀的方式来区分
//id加# class加. name加_ tagName不加前缀
switch (eleStr.substr(0, 1)) {
case '#':
return document.getElementById(eleStr.substr(1))
break
case '.':
return document.getElementsByClassName(eleStr.substr(1))
break
case '_':
return document.getElementsByName(eleStr.substr(1))// 查询元素的 name 属性
break
default:
return document.getElementsByTagName(eleStr)
break
}
}
13、防抖
// 防抖
function debounce(fn, delay) {
// 定时器
let timer = null
// 将debounce处理结果当作函数返回
return function () {
// 保留调用时的this上下文
let context = this
// 保留调用时传入的参数
let args = arguments
// 每次事件被触发时,都去清除之前的旧定时器
if (timer) {
clearTimeout(timer)
}
// 设立新定时器
timer = setTimeout(function () {
fn.apply(context, args)
}, delay)
}
}
function fun() {
console.log('fun')
}
const debounceTask = debounce(fun, 1000)
window.addEventListener('scroll', debounceTask)
14、节流
function throttle(fn, delay) {
let last = 0 // 上次触发时间
return (...args) => {
const now = Date.now()
if (now - last > delay) {
last = now
fn.apply(this, args)
}
}
}
// 测试
function task() {
console.log('run task')
}
const throttleTask = throttle(task, 1000)
window.addEventListener('scroll', throttleTask)
15、倒计时
// 倒计时
var now = (new Date()).valueOf();
var startTime = now.toString().substr(0, 10) //开始时间
var endTime = 1643904000; //结束时间
var lasttimer = setInterval(function () {
var ts = endTime - startTime; //计算剩余的毫秒数
if (ts > 0) {
var dd = parseInt(ts / 60 / 60 / 24, 10); //计算剩余的天数
var hh = parseInt(ts / 60 / 60 % 24, 10); //计算剩余的小时数
var mm = parseInt(ts / 60 % 60, 10); //计算剩余的分钟数
var ss = parseInt(ts % 60, 10); //计算剩余的秒数
dd = dd < 10 ? ('0' + dd) : dd
hh = hh < 10 ? ('0' + hh) : hh
mm = mm < 10 ? ('0' + mm) : mm
ss = ss < 10 ? ('0' + ss) : ss
$('.time').html('<span>' + dd + '</span>天<span>' + hh + '</span>时<span>' + mm + '</span>分<span>' + ss + '</span>秒')
startTime++;
} else if (ts < 0) {
$('.time').html('<span>00</span>天<span>00</span>时<span>00</span>分<span>00</span>秒')
clearInterval(lasttimer)
}
}, 1000);
16、输入框实时校验
// 输入框实时校验
$(window).load(function () {
$(".myinput").on("input propertychange", function () {
let str = $(this).val()
if (isNaN(str)) {
$(this).css('border', '2px solid red')
setTimeout(() => {
$(this).val('')//清空
}, 1000)
} else {
$(this).css('border', '1px solid #666')
}
})
})