JavaScript常用代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* ----------------------------------------------
* Code snippets of Javascript.
* The codes below are enlightened by the Buddha, so they must have no bugs.
_ooOoo_
o8888888o
88" . "88
(| -_- |)
O\ = /O
____/`---'\____
.' \\| |// `.
/ \\||| : |||// \
/ _||||| -:- |||||- \
| | \\\ - /// | |
| \_| ''\---/'' | |
\ .-\__ `-` ___/-. /
___`. .' /--.--\ `. . __
."" '< `.___\_<|>_/___.' >'"".
| | : `- \`.;`\ _ /`;.`/ - ` : | |
\ \ `-. \_ __\ /__ _/ .-` / /
======`-.____`-.___\_____/___.-`____.-'======
`=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
佛祖保佑 永无BUG
* ----------------------------------------------
*/

DOM

追加JS文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* 追加script脚本
* @param {*} src
*/
export function appendScript(src, callback) {
const myScript = document.createElement('script');
myScript.type = 'text/javascript';
myScript.src = src;

// 需要在这个script加载完成后,才能执行回调
if (myScript.readyState) { // IE
myScript.onreadystatechange = () => {
if (myScript.readyState === 'loaded' || myScript.readyState === 'complete') {
myScript.onreadystatechange = null;
if (typeof callback === 'function') {
callback();
}
}
};
} else { // 其他浏览器
myScript.onload = () => {
if (typeof callback === 'function') {
callback();
}
};
}

document.body.appendChild(myScript);
}
appendScript('https://unpkg.com/axios/dist/axios.min.js');
appendScript('https://s.thsi.cn/js/jquery-1.7.2.min.js');

获取元素的包围盒

1
2
3
4
5
// DOM
const { x, y, width, height, top, right, bottom, left } = document.querySelector('.play').getBoundingClientRect();

// D3.js
d3.select(this).node().getBoundingClientRect();

获取文本的绘制大小

注意这个方法获取的仅为文本,不包括文本的边距。

TypeScript:

1
2
3
4
5
function metureTextWidth(text: string, option: any): number {
const tmpContext = document.createElement('canvas').getContext('2d') as CanvasRenderingContext2D;
tmpContext.font = `${option.fontWeight} ${option.fontSize}px ${option.fontFamily}`;
return tmpContext.measureText(text).width;
}

JavaScript:

1
2
3
4
5
function metureTextWidth(text, option) {
const tmpContext = document.createElement('canvas').getContext('2d');
tmpContext.font = `${option.fontWeight} ${option.fontSize}px ${option.fontFamily}`;
return tmpContext.measureText(text).width;
}

事件

阻止冒泡

1
2
3
4
5
6
7
8
function stopBubble(e) {
e = e || window.event;
if (e.stopPropagation) {
e.stopPropagation(); // W3C阻止冒泡方法
} else {
e.cancelBubble = true; // IE阻止冒泡方法
}
}

获取鼠标坐标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* Get current coordinates of the mouse
* 只能在事件发生的“现场”调用,否则event和windows.event都是undefined
*/
function getCoordinatesOfMouse() {
const e = event || window.event;
const scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
const scrollY = document.documentElement.scrollTop || document.body.scrollTop;
const x = e.pageX || e.clientX + scrollX;
const y = e.pageY || e.clientY + scrollY;
return {
x,
y,
};
}

内存

获取变量占用的内存大小

https://blog.csdn.net/anmeiba2865/article/details/101813510

注意:字符串没有考虑中文的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
function memorySizeOf(obj) {
var bytes = 0;

function sizeOf(obj) {
if(obj !== null && obj !== undefined) {
switch(typeof obj) {
case 'number':
bytes += 8;
break;
case 'string':
bytes += obj.length * 2;
break;
case 'boolean':
bytes += 4;
break;
case 'object':
var objClass = Object.prototype.toString.call(obj).slice(8, -1);
if(objClass === 'Object' || objClass === 'Array') {
for(var key in obj) {
if(!obj.hasOwnProperty(key)) continue;
sizeOf(obj[key]);
}
} else bytes += obj.toString().length * 2;
break;
}
}
return bytes;
};

function formatByteSize(bytes) {
if(bytes < 1024) return bytes + " bytes";
else if(bytes < 1048576) return(bytes / 1024).toFixed(3) + " KiB";
else if(bytes < 1073741824) return(bytes / 1048576).toFixed(3) + " MiB";
else return(bytes / 1073741824).toFixed(3) + " GiB";
};

return formatByteSize(sizeOf(obj));
};

字符串

替换

1
2
3
4
const replaceAll = function (bigStr, str1, str2) { // 把bigStr中的所有str1替换为str2
const reg = new RegExp(str1, 'gm');
return bigStr.replace(reg, str2);
};

带样式的console输出

1
2
// rainbow
console.log('%c Rainbowww!', 'font-weight: bold; font-size: 50px;color: red; text-shadow: 3px 3px 0 rgb(217,31,38) , 6px 6px 0 rgb(226,91,14) , 9px 9px 0 rgb(245,221,8) , 12px 12px 0 rgb(5,148,68) , 15px 15px 0 rgb(2,135,206) , 18px 18px 0 rgb(4,77,145) , 21px 21px 0 rgb(42,21,113)');

md5

1
2
3
4
5
import * as crypto from 'crypto';
function md5(str) {
const md5Hander = crypto.createHash('md5');
return md5Hander.update(str).digest('hex');
}

将中文转为unicode编码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function unicode(str){
var value='';
for (var i = 0; i < str.length; i++) {
value += '\\u' + left_zero_4(parseInt(str.charCodeAt(i)).toString(16));
}
return value;
}
function left_zero_4(str) {
if (str != null && str != '' && str != 'undefined') {
if (str.length == 2) {
return '00' + str;
}
}
return str;
}

string转ASCII

1
2
3
4
5
6
7
export function stringToASCII(str) {
const strCodes = [];
for (let i = 0; i < str.length; i += 1) {
strCodes.push(str.charAt(i).charCodeAt());
}
return strCodes.join('');
}

数组

获取数组的最大值/最小值

1
2
3
const numbers = [5, 45822, 120, -215];
const maxInNumbers = Math.max.apply(Math, numbers); // 45822
const minInNumbers = Math.min.apply(Math, numbers); // -215

随机打乱数组

1
2
3
const users = ['张三', '李四', '王五']; 
users.sort(() => 0.5 - Math.random());
console.log(users);

对象

深拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function deepClone(obj) { 
if (obj === null) return null; // null 的情况
if (obj instanceof RegExp) return new RegExp(obj);
if (obj instanceof Date) return new Date(obj);
if (typeof obj !== 'object') {
// 如果不是复杂数据类型,直接返回
return obj;
}
/**
* 如果obj是数组,那么 obj.constructor 是 [Function: Array]
* 如果obj是对象,那么 obj.constructor 是 [Function: Object]
*/
const t = new obj.constructor();
for (const key in obj) {
// 如果 obj[key] 是复杂数据类型,递归
t[key] = deepClone(obj[key]);
}
return t;
}

合并对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* Deep Merge Attributes of Objects
* 合并多层级的对象的属性
*/
function deepMerge(target, obj) {
if (obj === null) {
return null;
}

if (obj instanceof RegExp) return new RegExp(obj);
if (obj instanceof Date) return new Date(obj);
if (typeof obj !== 'object') {
// 如果不是复杂数据类型,直接返回
return obj;
}

for (const key in obj) {
target[key] = deepMerge(target[key], obj[key]);
}

return target;
}

类型判断

1
2
3
4
5
6
7
function isArray(o) {
return toString.apply(o) === '[object Array]';
}

function isObject(o) {
return toString.apply(o) === '[object Object]';
}

日期

日期格式化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* Format Date to a String as you wish
eg: dateFormater('yyyy-MM-dd hh:mm:ss', new Date())
* @param {String} fmt
* @param {Date} date
*/
function dateFormater(fmt, date) {
const o = {
'M+': date.getMonth() + 1, // 月份
'd+': date.getDate(), // 日
'h+': date.getHours(), // 小时
'm+': date.getMinutes(), // 分
's+': date.getSeconds(), // 秒
'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
S: date.getMilliseconds(), // 毫秒
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (`${date.getFullYear()}`).substr(4 - RegExp.$1.length));
for (const k in o) if (new RegExp(`(${k})`).test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : ((`00${o[k]}`).substr((`${o[k]}`).length)));
return fmt;
}

字符串转Date对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function convertDateFromString(dateString) {
if (dateString) {
const date = new Date(dateString.replace(/-/, '/'));
return date;
}
}

export function stringToDate(str) {
str += '';
if (str.indexOf('/') !== -1) {
return new Date(str);
}
// 年月日
if (str.length === 8) {
return new Date(`${str.substr(0, 4)}/${str.substr(4, 2)}/${str.substr(6, 2)}`);
}
// 年月
if (str.length === 6) {
return new Date(`${str.substr(0, 4)}/${str.substr(4, 2)}`);
}
// 只有年份
if (str.length === 4) {
return new Date(str);
}
console.error(`日期格式不正确:${str}`);
return null;
}

HTTP

获取URL参数

1
2
3
const getURLParam = function (name) {
return decodeURIComponent((new RegExp(`[?|&]${name}=` + '([^&;]+?)(&|#|;|$)', 'ig').exec(location.search) || [, ''])[1].replace(/\+/g, '%20')) || null;
};

XMLHttpRequest

1
2
3
4
5
6
7
8
const xhr = new XMLHttpRequest();
xhr.open('get/post', url, true);
xhr.onreadystatechange = function () {
if (xjr.readyState == 4 && xhr.status == 200) {
alert();
}
};
xhr.send();

jQuery

1
2
3
4
5
6
7
8
9
10
11
12
13
$.ajax({
url,
type,
dataType: 'json',
timeout: 10000,
success(d) {
const { data } = d;
success && success(data);
},
error(e) {
error && error(e);
},
});

jsonp实现原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function jsonp(config) {
const options = config || {}; // 需要配置url, success, time, fail四个属性
const callbackName = (`jsonp_${Math.random()}`).replace('.', '');
const oHead = document.getElementsByTagName('head')[0];
const oScript = document.createElement('script');
oHead.appendChild(oScript);
window[callbackName] = function (json) { // 创建jsonp回调函数
oHead.removeChild(oScript);
clearTimeout(oScript.timer);
window[callbackName] = null;
options.success && options.success(json); // 先删除script标签,实际上执行的是success函数
};
oScript.src = `${options.url}?${callbackName}`; // 发送请求
if (options.time) { // 设置超时处理
oScript.timer = setTimeout(() => {
window[callbackName] = null;
oHead.removeChild(oScript);
options.fail && options.fail({
message: '超时',
});
}, options.time);
}
}
// 使用方法:
jsonp({
url: '/b.com/b.json',
success(d) {
// 数据处理
},
time: 5000,
fail() {
// 错误处理
},
});

获取用户IP

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* Get the real IP of client user
* The function can be valid in Egg.js framework
* @param {HTTP_Request} request
*/
function getClientIP(request) {
const ip = request.headers['x-forwarded-for'] // 判断是否有反向代理 IP
|| request.connection.remoteAddress // 判断 connection 的远程 IP
|| request.socket.remoteAddress // 判断后端的 socket 的 IP
|| request.connection.socket.remoteAddress;

return ip;
}

正则

电话号码

1
2
3
4
const validate = function (num) {
const reg = /^1[3-9]\d{9}$/;
return reg.test(num);
};

身份证

1
const reg = /^[1-9]{1}[0-9]{14}$|^[1-9]{1}[0-9]{16}([0-9]|[xX])$/;

IP

1
const reg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])(\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){3}$/;

中文

1
2
const reg = /.*[\u4e00-\u9fa5]+.*$/;
reg.test('123792739测试'); // true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
own.setCookie = function (cname, cvalue, exdays) {
const d = new Date();
d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
const expires = `expires=${d.toUTCString()}`;
document.cookie = `${cname}=${cvalue}; ${expires}`;
};
own.getCookie = function (cname) {
const name = `${cname}=`;
const ca = document.cookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1);
if (c.indexOf(name) != -1) return c.substring(name.length, c.length);
}
return '';
};

性能

防抖

1
2
3
4
5
6
7
8
9
function debounce(fn,wait=50) {
let timer;
return function(...args) {
if(timer) clearTimeout(timer)
timer = setTimeout(()=> {
fn.apply(this,args)
},wait)
}
}

节流

数学计算

生成指定范围的随机数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 生成单个
function randombetween(min, max) {
return min + (Math.random() * (max - min + 1));
}

/**
* Generate random numbers between the specified range
* 生成指定范围的随机数
*/
function generateRandomNumbersByRange(from, to, length) {
return Array.from({ length }, () => Math.random() * (to - from) + from);
}

/**
* Generate random numbers between the specified range with d3.js
* d3.js生成指定范围的随机数
*/
function generateRandomNumbersByRangeWithD3(from, to, length) {
const randomX = d3.randomNormal(from / 2, 80);
const randomY = d3.randomNormal(to / 2, 80);
return Array.from({ length }, () => [randomX(), randomY()]);
}

生成唯一ID(UUID)

1
2
3
4
5
6
7
export function generateUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}

绘图

监听帧数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 监听帧数
* 需要用闭包来保存过程变量
* @param {*} callback
*/
function onFramesPerSecond(callback)
{
var before, now, fps;
before = Date.now();
fps = 0;
requestAnimationFrame(
function loop() {
now = Date.now();
fps = Math.round(1000 / (now - before));
before = now;
requestAnimationFrame(loop);
if (callback && typeof callback === 'function') {
callback(fps)
}
}
);
}

文件操作

常用库

1
2
3
const http = require('http');
const path = require('path');
const fs = require('fs');

获取目录下的文件列表(不递归)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 获取目录下的文件列表(不递归)
* @param {*} dir
*/
function scanDir(dir) {
const fileNames = [];
const files = fs.readdirSync(dir);
for (let i = 0; i < files.length; i++) {
const fullPath = path.join(dir, files[i]);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
console.log('Directory');
} else {
console.log('File');
fileNames.push(files[i]);
}
}
return fileNames;
}

模拟form表单,POST上传文件,支持一次上传多个文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/**
* 模拟form表单,POST上传文件,支持一次上传多个文件
* 注意文件上传的原理(都是往请求对象中写数据):
* 1、写头部信息
* 2、写文件实体
* 3、写尾部信息
* @param {*} fileKeyValue
* @param {*} req
*/
function postFile(fileKeyValue, req) {
const boundaryKey = Math.random().toString(16);
const enddata = `\r\n----${boundaryKey}--`;

const files = [];
for (let i = 0; i < fileKeyValue.length; i++) {
const content = `\r\n----${boundaryKey}\r\n`
+ 'Content-Type: application/octet-stream\r\n'
+ `Content-Disposition: form-data; name="${fileKeyValue[i].urlKey}"; filename="${path.basename(fileKeyValue[i].urlValue)}"\r\n`
+ 'Content-Transfer-Encoding: binary\r\n\r\n';
const contentBinary = Buffer.from(content, 'utf-8'); // 当编码为ascii时,中文会乱码。
files.push({
contentBinary,
filePath: fileKeyValue[i].urlValue,
});
}
let contentLength = 0;
for (let i = 0; i < files.length; i++) {
const stat = fs.statSync(files[i].filePath);
contentLength += files[i].contentBinary.length;
contentLength += stat.size;
}

req.setHeader(
'Content-Type',
`multipart/form-data; boundary=--${boundaryKey}`,
);
req.setHeader('Content-Length', contentLength + Buffer.byteLength(enddata));

// 将参数发出
let fileindex = 0;
const doOneFile = function () {
req.write(files[fileindex].contentBinary);
const fileStream = fs.createReadStream(files[fileindex].filePath, {
bufferSize: 4 * 1024,
});
fileStream.pipe(req, { end: false });
fileStream.on('end', () => {
fileindex++;
if (fileindex === files.length) {
req.end(enddata);
} else {
doOneFile();
}
});
};
if (fileindex === files.length) {
req.end(enddata);
} else {
doOneFile();
}
}

上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
async function upload(filePath) {
const postfix = filePath.split('.').pop();

// 测试用例
// http://nodejs.org/api/http.html#http_http_request_options_callback
const files = [{ urlKey: postfix, urlValue: filePath }];
const options = {
host: 'datav.iwencai.com',
port: '80',
method: 'POST',
path: '/resource/api/file/upload',
};

return new Promise((resolve, reject) => {
const req = http.request(options, (res) => {
res.setEncoding('utf8');
res.on('data', (chunk) => {
console.log(`RAW BODY:${chunk}`);
let result = {
key: null,
};
try {
result = JSON.parse(chunk);
} catch (e) {
console.log(e);
}
setTimeout(() => {
resolve(result);
}, 500);
});
});

req.on('error', (e) => {
console.log(`problem with request:${e.message}`);
console.log(e);
setTimeout(() => {
reject(e);
}, 500);
});
postFile(files, req);
});
}