1. 自己实现一个模板引擎
function render(template, data) {
const reg = /\{\{(\w+)\}\}/; // 模板字符串正则
if (reg.test(template)) { // 判断模板里是否有模板字符串
const name = reg.exec(template)[1]; // 查找当前模板里第一个模板字符串的字段
template = template.replace(reg, data[name]); // 将第一个模板字符串渲染
return render(template, data); // 递归的渲染并返回渲染后的结构
}
return template; // 如果模板没有模板字符串直接返回
}
let template = '我是{{name}},年龄{{age}},性别{{sex}}';
let data = {
name: '姓名',
age: 18
}
render(template, data); // 我是姓名,年龄18,性别undefined
2. 查看各种时间
/**
* 查看各种时间
* @export
* @result
DNS查询耗时 :0
publicFunc.js?7fcd:9 TCP链接耗时 :0
publicFunc.js?7fcd:10 request请求耗时 :1
publicFunc.js?7fcd:11 解析dom树耗时 :-1597485845238
publicFunc.js?7fcd:12 白屏时间 :4
publicFunc.js?7fcd:13 domready时间 :504
publicFunc.js?7fcd:14 onload时间 :-1597485844734
publicFunc.js?7fcd:17 js内存使用占比 :96.83%
*/
export function consoleTime() {
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 (t = performance.memory) {
console.log('js内存使用占比 :' + (t.usedJSHeapSize / t.totalJSHeapSize * 100).toFixed(2) + '%')
}
})
}
3. arrayBuffer和String的相互转换
// arrayBufferToString
function ab2str(buf) {
return String.fromCharCode.apply(null, new Uint16Array(buf));
}
// stringToArrayBuffer
function str2ab(str) {
var buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char
var bufView = new Uint16Array(buf);
for (var i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
4. 判断是否是闰年
判断是否为闰年, isLeapYear通过返回bool值来确定年份是否为闰年。 是闰年的判断条件有2个 。
- 世纪年能被400整除的是闰年。(如2000年是闰年,1900年不是闰年)
- 普通年能被4整除且不能被100整除的为闰年。(如2004年就是闰年,1900年不是闰年)
只要满足这两个条件之一,就能确定是闰年
/**
* @TODO 判断是否为闰年
* @date 2012-8-9
* @param intYear 代表年份的值
* @return true 是闰年 false不是闰年
*/
export function isLeapYear(intYear) {
if (intYear % 100 == 0) {
if (intYear % 400 == 0) {
return true;
}
} else {
if ((intYear % 4) == 0) {
return true;
}
}
return false;
}
5. toFixed的精度问题及修正方法。
1.35.toFixed(1) // 1.4 正确
1.335.toFixed(2) // 1.33 错误
1.3335.toFixed(3) // 1.333 错误
1.33335.toFixed(4) // 1.3334 正确
1.333335.toFixed(5) // 1.33333 错误
1.3333335.toFixed(6) // 1.333333 错误
解决toFixed。 在Number原型上重写 toFixed方法
我们通过判断最后一位是否大于等于5来决定需不需要进位,如果需要进位先把小数乘以倍数变为整数,加1之后,再除以倍数变为小数,这样就不用一位一位的进行判断
// toFixed兼容方法
Number.prototype.toFixed = function(len){
if(len>20 || len<0){
throw new RangeError('toFixed() digits argument must be between 0 and 20');
}
// .123转为0.123
var number = Number(this);
if (isNaN(number) || number >= Math.pow(10, 21)) {
return number.toString();
}
if (typeof (len) == 'undefined' || len == 0) {
return (Math.round(number)).toString();
}
var result = number.toString(),
numberArr = result.split('.');
if(numberArr.length<2){
//整数的情况
return padNum(result);
}
var intNum = numberArr[0], //整数部分
deciNum = numberArr[1],//小数部分
lastNum = deciNum.substr(len, 1);//最后一个数字
if(deciNum.length == len){
//需要截取的长度等于当前长度
return result;
}
if(deciNum.length < len){
//需要截取的长度大于当前长度 1.3.toFixed(2)
return padNum(result)
}
//需要截取的长度小于当前长度,需要判断最后一位数字
result = intNum + '.' + deciNum.substr(0, len);
if(parseInt(lastNum, 10)>=5){
//最后一位数字大于5,要进位
var times = Math.pow(10, len); //需要放大的倍数
var changedInt = Number(result.replace('.',''));//截取后转为整数
changedInt++;//整数进位
changedInt /= times;//整数转为小数,注:有可能还是整数
result = padNum(changedInt+'');
}
return result;
//对数字末尾加0
function padNum(num){
var dotPos = num.indexOf('.');
if(dotPos === -1){
//整数的情况
num += '.';
for(var i = 0;i<len;i++){
num += '0';
}
return num;
} else {
//小数的情况
var need = len - (num.length - dotPos - 1);
for(var j = 0;j<need;j++){
num += '0';
}
return num;
}
}
}
6. 将字符串的空格去除
export function trim(str, pos = 'both') {
if (pos == 'both') {
return str.replace(/^\s+|\s+$/g, "");
} else if (pos == "left") {
return str.replace(/^\s*/, '');
} else if (pos == 'right') {
return str.replace(/(\s*$)/g, "");
} else if (pos == 'all') {
return str.replace(/\s+/g, "");
} else {
return str;
}
}
7. 自动忽略console.log语句
在项目的根目录或者 main.js 引入这个函数并执行一次,就可以实现在本地环境显示console, 其他环境忽略 console.log 语句的效果。
export function rewriteLog() {
console.log = (function (log) {
return process.env.NODE_ENV === 'development'? log : function() {}
}(console.log))
}
8. 复制内容到剪贴板
原理:
- 创建一个textare元素并调用select()方法选中
- document.execCommand('copy')方法,拷贝当前选中内容到剪贴板
export function copyToBoard(value) {
const element = document.createElement('textarea')
document.body.appendChild(element)
element.value = value
element.select()
if (document.execCommand('copy')) {
document.execCommand('copy')
document.body.removeChild(element)
return true
}
document.body.removeChild(element)
return false
}
9. 对象转化为FormData对象
使用场景:上传文件时我们要新建一个FormData对象,然后有多少个参数就append多少次,使用该函数可以简化逻辑
/**
* 对象转化为formdata
* @param {Object} object
*/
export function getFormData(object) {
const formData = new FormData()
Object.keys(object).forEach(key => {
const value = object[key]
if (Array.isArray(value)) {
value.forEach((subValue, i) =>
formData.append(key + `[${i}]`, subValue)
)
} else {
formData.append(key, object[key])
}
})
return formData
}
10. 生成随机字符串
方法1. 通过for循环将随机字符串遍历添加到返回结果中(推荐使用)
/**
* 生成随机字符串
* @param {string} chars
* @param {number} length
* @returns string
*/
export function uuid(chars, length = 4) {
chars = chars || "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678" // 去除了一些容易有歧义的字母和数字
let res = ''
for (var i = length; i > 0; --i) {
res += chars[Math.floor(Math.random() * chars.length)]
}
return res
}
方法2. Math.random().toString(36).slice(-4);
Math.random() // 生成随机数字
.toString(36) // 转化成36进制: "0.ihtkybjh3t"
.slice(-4) // 截取后四位 "jh3t"
方法2缺点:
-
只能生成有 0-9、a-z字符组成的字符串
-
由于
Math.random()生成的18位小数,可能无法填充36位,最后几个字符串,只能在指定的几个字符中选择。导致随机性降低。 -
某些情况下会返回空值。例如,当随机数为 0, 0.5, 0.25, 0.125...时,返回为空值
11. 深度冻结
/**
* 深冻结
* 冻结对象 Object.freeze(obj)。 但是这种办法只能冻结一层。如果有多层就不起作用。 比如对象内部有数组或对象就无效。 所以需要遍历去深度冻结对象
* @param {*} obj 传入的对象参数
* result 结果和传参一致
*/
export function deepFreeze(obj) {
if (!Object.isFrozen(obj)) {
Object.freeze(obj)
}
for (let key in obj) {
if (!obj.hasOwnProperty(key) || !_.isObject(obj[key])) {
continue
}
this.deepFreeze(obj[key])
}
}