JavaScript有用的代码片段和trick
# 浮点数取整
const x = 123.4545;
x >> 0; // 123
~~x; // 123
x | 0; // 123
Math.floor(x); // 123
2
3
4
5
注意:前三种方法只适用于 32 个位整数,对于负数的处理上和 Math.floor 是不同的。
Math.floor(-12.53); // -13
-12.53 | 0; // -12
2
# 生成 6 位数字验证码
// 方法一
("000000" + Math.floor(Math.random() * 999999)).slice(-6);
// 方法二
Math.random().toString().slice(-6);
// 方法三
Math.random().toFixed(6).slice(-6);
// 方法四
"" + Math.floor(Math.random() * 999999);
2
3
4
5
6
7
8
9
10
11
# 16 进制颜色代码生成
(function () {
return (
"#" + ("00000" + ((Math.random() * 0x1000000) << 0).toString(16)).slice(-6)
);
})();
2
3
4
5
# 驼峰命名转下划线
"componentMapModelRegistry"
.match(/^[a-z][a-z0-9]+|[A-Z][a-z0-9]*/g)
.join("_")
.toLowerCase(); // component_map_model_registry
2
3
4
# url 查询参数转 json 格式
// ES6
const query = (search = "") =>
((querystring = "") =>
((q) => (
querystring
.split("&")
.forEach((item) =>
((kv) => kv[0] && (q[kv[0]] = kv[1]))(item.split("="))
),
q
))({}))(search.split("?")[1]);
// 对应ES5实现
var query = function (search) {
if (search === void 0) {
search = "";
}
return (function (querystring) {
if (querystring === void 0) {
querystring = "";
}
return (function (q) {
return (
querystring.split("&").forEach(function (item) {
return (function (kv) {
return kv[0] && (q[kv[0]] = kv[1]);
})(item.split("="));
}),
q
);
})({});
})(search.split("?")[1]);
};
query("?key1=value1&key2=value2"); // es6.html:14 {key1: "value1", key2: "value2"}
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
# 获取 URL 参数
function getQueryString(key) {
var reg = new RegExp("(^|&)" + key + "=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if (!!r) {
return unescape(r[2]);
}
return null;
}
2
3
4
5
6
7
8
# n 维数组展开成一维数组
var foo = [1, [2, 3], ["4", 5, ["6", 7, [8]]], [9], 10];
// 方法一
// 限制:数组项不能出现`,`,同时数组项全部变成了字符数字
foo.toString().split(","); // ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
// 方法二
// 转换后数组项全部变成数字了
eval("[" + foo + "]"); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 方法三,使用ES6展开操作符
// 写法太过麻烦,太过死板
[1, ...[2, 3], ...["4", 5, ...["6", 7, ...[8]]], ...[9], 10]; // [1, 2, 3, "4", 5, "6", 7, 8, 9, 10]
// 方法四
JSON.parse(`[${JSON.stringify(foo).replace(/\[|]/g, "")}]`); // [1, 2, 3, "4", 5, "6", 7, 8, 9, 10]
// 方法五
const flatten = (ary) =>
ary.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []);
flatten(foo); // [1, 2, 3, "4", 5, "6", 7, 8, 9, 10]
// 方法六
function flatten(a) {
return Array.isArray(a) ? [].concat(...a.map(flatten)) : a;
}
flatten(foo); // [1, 2, 3, "4", 5, "6", 7, 8, 9, 10]
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
注:更多方法请参考《How to flatten nested array in JavaScript?》
# 日期格式化
// 方法一
function format1(x, y) {
var z = {
y: x.getFullYear(),
M: x.getMonth() + 1,
d: x.getDate(),
h: x.getHours(),
m: x.getMinutes(),
s: x.getSeconds(),
};
return y.replace(/(y+|M+|d+|h+|m+|s+)/g, function (v) {
return ((v.length > 1 ? "0" : "") + eval("z." + v.slice(-1))).slice(
-(v.length > 2 ? v.length : 2)
);
});
}
format1(new Date(), "yy-M-d h:m:s"); // 17-10-14 22:14:41
// 方法二
Date.prototype.format = function (fmt) {
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
S: this.getMilliseconds(), //毫秒
};
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(
RegExp.$1,
(this.getFullYear() + "").substr(4 - RegExp.$1.length)
);
}
for (var 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;
};
new Date().format("yy-M-d h:m:s"); // 17-10-14 22:18:17
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
# 统计文字个数
function wordCount(data) {
var pattern =
/[a-zA-Z0-9_\u0392-\u03c9]+|[\u4E00-\u9FFF\u3400-\u4dbf\uf900-\ufaff\u3040-\u309f\uac00-\ud7af]+/g;
var m = data.match(pattern);
var count = 0;
if (m === null) return count;
for (var i = 0; i < m.length; i++) {
if (m[i].charCodeAt(0) >= 0x4e00) {
count += m[i].length;
} else {
count += 1;
}
}
return count;
}
var text =
"贷款买房,也意味着你能给自己的资产加杠杆,能够撬动更多的钱,来孳生更多的财务性收入。";
wordCount(text); // 38
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 特殊字符转义
function htmlspecialchars(str) {
var str = str
.toString()
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """);
return str;
}
htmlspecialchars("&jfkds<>"); // "&jfkds<>"
2
3
4
5
6
7
8
9
10
11
# 动态插入 js
function injectScript(src) {
var s, t;
s = document.createElement("script");
s.type = "text/javascript";
s.async = true;
s.src = src;
t = document.getElementsByTagName("script")[0];
t.parentNode.insertBefore(s, t);
}
2
3
4
5
6
7
8
9
# 格式化数量
// 方法一
function formatNum(num, n) {
if (typeof num == "number") {
num = String(num.toFixed(n || 0));
var re = /(-?\d+)(\d{3})/;
while (re.test(num)) num = num.replace(re, "$1,$2");
return num;
}
return num;
}
formatNum(2313123, 3); // "2,313,123.000"
// 方法二
"2313123".replace(/\B(?=(\d{3})+(?!\d))/g, ","); // "2,313,123"
// 方法三
function formatNum(str) {
return str
.split("")
.reverse()
.reduce((prev, next, index) => {
return (index % 3 ? next : next + ",") + prev;
});
}
formatNum("2313323"); // "2,313,323"
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 chechCHNCardId(sNo) {
if (!this.regExpTest(sNo, /^[0-9]{17}[X0-9]$/)) {
return false;
}
sNo = sNo.toString();
var a, b, c;
a =
parseInt(sNo.substr(0, 1)) * 7 +
parseInt(sNo.substr(1, 1)) * 9 +
parseInt(sNo.substr(2, 1)) * 10;
a =
a +
parseInt(sNo.substr(3, 1)) * 5 +
parseInt(sNo.substr(4, 1)) * 8 +
parseInt(sNo.substr(5, 1)) * 4;
a =
a +
parseInt(sNo.substr(6, 1)) * 2 +
parseInt(sNo.substr(7, 1)) * 1 +
parseInt(sNo.substr(8, 1)) * 6;
a =
a +
parseInt(sNo.substr(9, 1)) * 3 +
parseInt(sNo.substr(10, 1)) * 7 +
parseInt(sNo.substr(11, 1)) * 9;
a =
a +
parseInt(sNo.substr(12, 1)) * 10 +
parseInt(sNo.substr(13, 1)) * 5 +
parseInt(sNo.substr(14, 1)) * 8;
a = a + parseInt(sNo.substr(15, 1)) * 4 + parseInt(sNo.substr(16, 1)) * 2;
b = a % 11;
if (b == 2) {
c = sNo.substr(17, 1).toUpperCase();
} else {
c = parseInt(sNo.substr(17, 1));
}
switch (b) {
case 0:
if (c != 1) {
return false;
}
break;
case 1:
if (c != 0) {
return false;
}
break;
case 2:
if (c != "X") {
return false;
}
break;
case 3:
if (c != 9) {
return false;
}
break;
case 4:
if (c != 8) {
return false;
}
break;
case 5:
if (c != 7) {
return false;
}
break;
case 6:
if (c != 6) {
return false;
}
break;
case 7:
if (c != 5) {
return false;
}
break;
case 8:
if (c != 4) {
return false;
}
break;
case 9:
if (c != 3) {
return false;
}
break;
case 10:
if (c != 2) {
return false;
}
}
return true;
}
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# 测试质数
function isPrime(n) {
return !/^.?$|^(..+?)\1+$/.test("1".repeat(n));
}
2
3
# 统计字符串中相同字符出现的次数
var arr = "abcdaabc";
var info = arr.split("").reduce((p, k) => (p[k]++ || (p[k] = 1), p), {});
console.log(info); //{ a: 3, b: 2, c: 2, d: 1 }
2
3
4
5
# 使用void 0
来解决undefined
被污染问题
undefined = 1;
!!undefined; // true
!!void 0; // false
2
3
# 单行写一个评级组件
"★★★★★☆☆☆☆☆".slice(5 - rate, 10 - rate);
# JavaScript 错误处理的方式的正确姿势
try {
something;
} catch (e) {
window.location.href = "http://stackoverflow.com/search?q=[js]+" + e.message;
}
2
3
4
5
# 匿名函数自执行写法
(function () {})();
(function () {})();
[(function () {})()];
~(function () {})();
!(function () {})();
+(function () {})();
-(function () {})();
delete (function () {})();
typeof (function () {})();
void (function () {})();
new (function () {})();
new (function () {})();
var f = (function () {})();
1, (function () {})();
1 ^ (function () {})();
1 > (function () {})();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 两个整数交换数值
var a = 20,
b = 30;
a ^= b;
b ^= a;
a ^= b;
a; // 30
b; // 20
2
3
4
5
6
7
8
# 数字字符转数字
var a = "1";
+a; // 1
2
# 最短的代码实现数组去重
[...new Set([1, "1", 2, 1, 1, 3])]; // [1, "1", 2, 3]
# 用最短的代码实现一个长度为 m(6)且值都 n(8)的数组
Array(6).fill(8); // [8, 8, 8, 8, 8, 8]
# 将 argruments 对象转换成数组
var argArray = Array.prototype.slice.call(arguments);
// ES6:
var argArray = Array.from(arguments);
// or
var argArray = [...arguments];
2
3
4
5
6
7
# 获取日期时间缀
// 获取指定时间的时间缀
new Date().getTime();
new Date().getTime();
new Date().getTime();
// 获取当前的时间缀
Date.now();
// 日期显示转换为数字
+new Date();
2
3
4
5
6
7
8
# 使用~x.indexOf('y')
来简化x.indexOf('y') > -
var str = "hello world";
if (str.indexOf("lo") > -1) {
// ...
}
if (~str.indexOf("lo")) {
// ...
}
2
3
4
5
6
7
8
# parseInt()
or Number()
两者的差别之处在于解析和转换两者之间的理解。
解析允许字符串中含有非数字字符,解析按从左到右的顺序,如果遇到非数字字符就停止。而转换不允许出现非数字字符,否者会失败并返回 NaN。
var a = "520";
var b = "520px";
Number(a); // 520
parseInt(a); // 520
Number(b); // NaN
parseInt(b); // 520
2
3
4
5
6
7
8
parseInt
方法第二个参数用于指定转换的基数,ES5 默认为 10 进制。
parseInt("10", 2); // 2
parseInt("10", 8); // 8
parseInt("10", 10); // 10
parseInt("10", 16); // 16
2
3
4
对于网上parseInt(0.0000008)
的结果为什么为 8,原因在于 0.0000008 转换成字符为"8e-7",然后根据parseInt
的解析规则自然得到"8"这个结果。
# +
拼接操作,+x
or String(x)
?
+运算符可用于数字加法,同时也可以用于字符串拼接。如果+的其中一个操作符是字符串(或者通过 隐式强制转换可以得到字符串),则执行字符串拼接;否者执行数字加法。
需要注意的时对于数组而言,不能通过valueOf()
方法得到简单基本类型值,于是转而调用toString()
方法。
[1, 2] + [3, 4]; // "1,23,4"
对于对象同样会先调用valueOf()
方法,然后通过toString()
方法返回对象的字符串表示。
var a = {};
a + 123; // "[object Object]123"
2
对于a + ""
隐式转换和String(a)
显示转换有一个细微的差别:a + ''
会对 a 调用valueOf()
方法,而String()
直接调用toString()
方法。大多数情况下我们不会考虑这个问题,除非真遇到。
var a = {
valueOf: function () {
return 42;
},
toString: function () {
return 4;
},
};
a + ""; // 42
String(a); // 4
2
3
4
5
6
7
8
9
10
11
# 判断对象的实例
// 方法一: ES3
function Person(name, age) {
if (!(this instanceof Person)) {
return new Person(name, age);
}
this.name = name;
this.age = age;
}
// 方法二: ES5
function Person(name, age) {
var self = this instanceof Person ? this : Object.create(Person.prototype);
self.name = name;
self.age = age;
return self;
}
// 方法三:ES6
function Person(name, age) {
if (!new.target) {
throw "Peron must called with new";
}
this.name = name;
this.age = age;
}
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
# 数据安全类型检查
// 对象
function isObject(value) {
return Object.prototype.toString.call(value).slice(8, -1) === 'Object'';
}
// 数组
function isArray(value) {
return Object.prototype.toString.call(value).slice(8, -1) === 'Array';
}
// 函数
function isFunction(value) {
return Object.prototype.toString.call(value).slice(8, -1) === 'Function';
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# 让数字的字面值看起来像对象
2.toString(); // Uncaught SyntaxError: Invalid or unexpected token
2..toString(); // 第二个点号可以正常解析
2 .toString(); // 注意点号前面的空格
(2).toString(); // 2先被计算
2
3
4
5
# 对象可计算属性名(仅在 ES6 中)
var suffix = " name";
var person = {
["first" + suffix]: "Nicholas",
["last" + suffix]: "Zakas",
};
person["first name"]; // "Nicholas"
person["last name"]; // "Zakas"
2
3
4
5
6
7
8
# 数字四舍五入
// v: 值,p: 精度
function (v, p) {
p = Math.pow(10, p >>> 31 ? 0 : p | 0)
v *= p;
return (v + 0.5 + (v >> 31) | 0) / p
}
round(123.45353, 2); // 123.45
2
3
4
5
6
7
8
# 在浏览器中根据 url 下载文件
function download(url) {
var isChrome = navigator.userAgent.toLowerCase().indexOf("chrome") > -1;
var isSafari = navigator.userAgent.toLowerCase().indexOf("safari") > -1;
if (isChrome || isSafari) {
var link = document.createElement("a");
link.href = url;
if (link.download !== undefined) {
var fileName = url.substring(url.lastIndexOf("/") + 1, url.length);
link.download = fileName;
}
if (document.createEvent) {
var e = document.createEvent("MouseEvents");
e.initEvent("click", true, true);
link.dispatchEvent(e);
return true;
}
}
if (url.indexOf("?") === -1) {
url += "?download";
}
window.open(url, "_self");
return true;
}
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
# 快速生成 UUID
function uuid() {
var d = new Date().getTime();
var uuid = "xxxxxxxxxxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
/[xy]/g,
function (c) {
var r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c == "x" ? r : (r & 0x3) | 0x8).toString(16);
}
);
return uuid;
}
uuid(); // "33f7f26656cb-499b-b73e-89a921a59ba6"
2
3
4
5
6
7
8
9
10
11
12
13
14
# JavaScript 浮点数精度问题
function isEqual(n1, n2, epsilon) {
epsilon = epsilon == undefined ? 10 : epsilon; // 默认精度为10
return n1.toFixed(epsilon) === n2.toFixed(epsilon);
}
0.1 + 0.2; // 0.30000000000000004
isEqual(0.1 + 0.2, 0.3); // true
0.7 + 0.1 + 99.1 + 0.1; // 99.99999999999999
isEqual(0.7 + 0.1 + 99.1 + 0.1, 100); // true
2
3
4
5
6
7
8
9
10
# 格式化表单数据
function formatParam(obj) {
var query = "",
name,
value,
fullSubName,
subName,
subValue,
innerObj,
i;
for (name in obj) {
value = obj[name];
if (value instanceof Array) {
for (i = 0; i < value.length; ++i) {
subValue = value[i];
fullSubName = name + "[" + i + "]";
innerObj = {};
innerObj[fullSubName] = subValue;
query += formatParam(innerObj) + "&";
}
} else if (value instanceof Object) {
for (subName in value) {
subValue = value[subName];
fullSubName = name + "[" + subName + "]";
innerObj = {};
innerObj[fullSubName] = subValue;
query += formatParam(innerObj) + "&";
}
} else if (value !== undefined && value !== null)
query += encodeURIComponent(name) + "=" + encodeURIComponent(value) + "&";
}
return query.length ? query.substr(0, query.length - 1) : query;
}
var param = {
name: "jenemy",
likes: [0, 1, 3],
memberCard: [
{ title: "1", id: 1 },
{ title: "2", id: 2 },
],
};
formatParam(param); // "name=12&likes%5B0%5D=0&likes%5B1%5D=1&likes%5B2%5D=3&memberCard%5B0%5D%5Btitle%5D=1&memberCard%5B0%5D%5Bid%5D=1&memberCard%5B1%5D%5Btitle%5D=2&memberCard%5B1%5D%5Bid%5D=2"
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
# 创建指定长度非空数组
在 JavaScript 中可以通过new Array(3)
的形式创建一个长度为 3 的空数组。在老的 Chrome 中其值为[undefined x 3],在最新的 Chrome 中为[empty x 3],即空单元数组。在老 Chrome 中,相当于显示使用[undefined, undefined, undefined]
的方式创建长度为 3 的数组。
但是,两者在调用map()
方法的结果是明显不同的
var a = new Array(3);
var b = [undefined, undefined, undefined];
a.map((v, i) => i); // [empty × 3]
b.map((v, i) => i); // [0, 1, 2]
2
3
4
5
多数情况我们期望创建的是包含undefined
值的指定长度的空数组,可以通过下面这种方法来达到目的:
var a = Array.apply(null, { length: 3 });
a; // [undefined, undefined, undefined]
a.map((v, i) => i); // [0, 1, 2]
2
3
4
总之,尽量不要创建和使用空单元数组。
# debounce 方法
debounce()
方法用来延迟执行函数。
var debounce = function (func, threshold, execAsap) {
var timeout;
return function debounced() {
var obj = this,
args = arguments;
function delayed() {
if (!execAsap) func.apply(obj, args);
timeout = null;
}
if (timeout) clearTimeout(timeout);
else if (execAsap) func.apply(obj, args);
timeout = setTimeout(delayed, threshold || 100);
};
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 判断客户端
var browser = {
v: (function () {
var u = navigator.userAgent,
app = navigator.appVersion,
p = navigator.platform;
return {
trident: u.indexOf("Trident") > -1, //IE内核
presto: u.indexOf("Presto") > -1, //opera内核
webKit: u.indexOf("AppleWebKit") > -1, //苹果、谷歌内核
gecko: u.indexOf("Gecko") > -1 && u.indexOf("KHTML") == -1, //火狐内核
mobile: !!u.match(/AppleWebKit.*Mobile.*/), //是否为移动终端
ios: !!u.match(/i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端
android: u.indexOf("Android") > -1 || u.indexOf("Linux") > -1, //android终端或uc浏览器
iPhone: u.indexOf("iPhone") > -1, //是否为iPhone或者QQHD浏览器
iPad: u.indexOf("iPad") > -1, //是否iPad
weixin: u.indexOf("MicroMessenger") > -1, //是否微信
webApp: u.indexOf("Safari") == -1, //是否web应该程序,没有头部与底部
UCB: u.match(/UCBrowser/i) == "UCBrowser",
QQB: u.match(/MQQBrowser/i) == "MQQBrowser",
win: p.indexOf("Win") > -1, //判断是否是WIN操作系统
mac: p.indexOf("Mac") > -1, //判断是否是Mac操作系统
};
})(),
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24