推荐的网站: www.30secondsofcode.org/
1. 判断类型
const isNull = (params) => {
return Object.prototype.toString.call(params) == "[object Null]"
}
const isUndefined = (params) => {
return Object.prototype.toString.call(params) == "[object Undefined]"
}
const isNil = (value) => {
return isNull(value) || isUndefined(value)
}
const isString = (params) => {
return Object.prototype.toString.call(params) == "[object String]"
}
const isNumber = (params) => {
return Object.prototype.toString.call(params) == "[object Number]"
}
const isBoolean = (params) => {
return Object.prototype.toString.call(params) == "[object Boolean]"
}
2. 表情包正则
// 表情包
const emojiReg = /[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF][\u200D|\uFE0F]|[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF]|[0-9|*|#]\uFE0F\u20E3|[0-9|#]\u20E3|[\u203C-\u3299]\uFE0F\u200D|[\u203C-\u3299]\uFE0F|[\u2122-\u2B55]|\u303D|[\A9|\AE]\u3030|\uA9|\uAE|\u3030/;
3. 数字转千分位数字
/**
* 数字转为千分位数字
* @param {*} num 需要格式化的数字
*/
const thousandNum = (num) => {
if (isNumber(num)) {
return num.toLocaleString()
}
if (isString(num)) {
return num.replace(/\B(?=(\d{3})+(?!\d))/g, ",")
}
}
4. 地址栏参【字符串】与【对象】互相转换
/**
* @param url String 带参数url
* @return Object 地址栏参数键值对集合
*/
const urlSearchParams = (url) => {
let params = {};
if (url) {
let reg = /[?#&=]([^?=&#]+)(?:=([^&#]*))?/g;
url.replace(reg, (...arg) => {
let [res, key, value] = arg;
params[key] = value;
});
}
return params;
}
// 参数转换成对象
const getURLParameters = (url) =>
(url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce(
(a, v) => (
(a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1)), a
),
{}
)
getURLParameters('google.com') // {}
getURLParameters('http://url.com/page?name=Adam&surname=Smith')
// {name: 'Adam', surname: 'Smith'}
/**
*
* 将对象拼接成url参数形式
* @param {*} object 参数对象
* @return String
*/
const objectToString = (object) => {
return Object.keys(object).map(key => key + '=' + object[key]).join('&')
}
/**
* 拼接成带有参数的url
*
* @param {String} baseUrl
* @param {Object} paramsObject 需要拼接的对象
* @returns String
*/
const jointUrl = (baseUrl, paramsObject) => {
if (!Object.keys(paramsObject).length) return baseUrl;
let params = objectToString(paramsObject)
return `${baseUrl}?${params}`
}'
将 url 问号后面的查询字符串转为对象
const query = 'name=John&age=30'; // 将字符串解析为对象
const parseQuery = query => Object.fromEntries(new URLSearchParams(query));
// 结果: parseQuery = { name: 'John', age: '30' }
5. url域名替换与查找
// 替换
_url = _url.replace(/\w+(?=.com)/, 'yjzf')
6. 深拷贝
/**
* 深拷贝
* @param {*} obj
* @returns
*/
const deepClone = obj => {
let objClone = Array.isArray(obj) ? [] : {};
if (obj && typeof obj === "object") {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
//判断obj子元素是否为对象,如果是,递归复制
if (obj[key] && typeof obj[key] === "object") {
objClone[key] = deepClone(obj[key]);
} else {
//如果不是,简单复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
7. 获取阿里云视频资源第一帧截图
/**
* 获取阿里云视频资源第一帧截图
* @return[String] 第一帧截图
*/
const frameImg = (url, size = '0x0', t = '0') => {
const w = size.split('x')[0]
const h = size.split('x')[1]
return `${url}?x-oss-process=video/snapshot,t_${t},f_jpg,w_${w},h_${h},m_fast`
}
8. 字符串替换成 【*】
/**
* 从第一位开始到最后一位,中间的字符串替换为3个 *
* @param {*} str
* @returns
*/
const replaceFixedString = (str) => {
return str.replace(/^(.{1})(.*)(.{1})$/, '$1***$3')
}
replaceFixedString('12327')//'1***7'
/**
* 从第一位开始到最后一位,中间的字符串都替换成 *
*
* 数字替换
* res = a.replace(/^(\d{2})(.*?)(\d{2})$/, (match, p1, p2, p3)=>p1+p2.replace(/./g, "*")+p3)
* @param {*} str
* @returns
*/
const replaceString = (str) => {
return str.replace(/^(.{1})(.*)(.{1})$/, (match, p1, p2, p3) => p1 + p2.replace(/./g, "*") + p3)
}
replaceString('123416')//'1****6'
9. 日期格式化
/**
* 格式化日期
*
* @param {*} date 日期
* @param {*} fmt 任意格式
* @returns
*/
export function friendlyFormatDate(date, fmt = 'yyyy-MM-dd HH:mm:ss') {
if (!date) return ''
let _date = new Date(+date)
let ret;
const opt = {
"y+": _date.getFullYear().toString(), // 年
"M+": (_date.getMonth() + 1).toString(), // 月
"d+": _date.getDate().toString(), // 日
"H+": _date.getHours().toString(), // 时
"m+": _date.getMinutes().toString(), // 分
"s+": _date.getSeconds().toString() // 秒
};
for (let k in opt) {
ret = new RegExp("(" + k + ")").exec(fmt);
if (ret) {
fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
};
};
return fmt;
}
10. 判断url是否含有【?】正则
reg = /.*\?\.*/;
11. 截取两个字符串之间/之后/中间的内容
// 1、js截取两个字符串之间的内容:
var str = "aaabbbcccdddeeefff";
str = str.match(/aaa([\s\S]*?)fff/)[1];
console.log(str);//结果bbbcccdddeee
//2、js截取某个字符串前面的内容: var str = "aaabbbcccdddeeefff";
str = str.match(/(\S*)fff/)[1];
console.log(str);//结果aaabbbcccdddeee
//3、js截取某个字符串后面的内容: var str = "aaabbbcccdddeeefff";
str = str.match(/aaa(\S*)/)[1];
console.log(str);//结果bbbcccdddeeefff
//4、js全局截取两个字符串之间的内容: var str = 'abcdabcdabcd'
str = str.match(/a([\s\S]*?)d/g);
var res = str.toString().replace(/a/g,'').replace(/d/g,'');
console.log(res); //结果bc,bc,bc
12. 数组按某个字符串属性排序
let list = [
{ brandName: '埃安', id: 1, pinyin: 'AIAN' },
{ brandName: '宝马', id: 4, pinyin: 'BAOMA' },
{ brandName: '爱驰', id: 2, pinyin: 'AICHIQICHE' },
{ brandName: '保时捷', id: 5, pinyin: 'BAOSHIJIE' },
{ brandName: '宝马M', id: 6, pinyin: 'BAOMAM' },
{ brandName: '奥迪', id: 3, pinyin: 'AODI' }
]
list.sort((a, b) => a.pinyin.localeCompare(b.pinyin))
13. 月份补零
let str = 9
const monthStr = ('0' + month).slice(-2)
console.log(monthStr);// '09'
const monthStr = (month + '').padStart(2, '0')//'09'
const str1 = '5';
console.log(str1.padStart(2, '0'));
// Expected output: "05"
14. 匹配图片相关的后缀名
const reg = /^(.*)\.(jpg|png|jpeg)$/
console.log(reg.test('111.png'))//true
console.log(reg.test('111.png1'))//false
15. 获取图片后缀名
const replaceString = (str) => {
return str.replace(/^(.*)\.(jpg|png|jpeg)$/, (match, p1, p2,) => p2)
}
replaceString('tesatt.png')//png
16. 获取字符串中的指定字符
const result = (str) => {
return str.replace(/^http:\/\/tmp(.*)\.(jpg|png|jpeg)$/, (match, p1, p2) => {
console.log(p1,'p1')
console.log(p2,'p2')
return p1 + '.' + p2
})
}
let str = 'http://tmp/YdbWDYntvJlucfb97bd5c61696f0b30136b64c6a5b08.png'
console.log(result(str))
去掉tmp后的/
const result = (str) => {
return str.replace(/^http:\/\/tmp(\S{1})(.*)\.(jpg|png|jpeg)$/, (match, p1, p2, p3) => {
console.log(p1,'p1')
console.log(p2,'p2')
console.log(p3,'p3')
return p2 + '.' + p3
})
}
let str = 'http://tmp/YdbWDYntvJlucfb97bd5c61696f0b30136b64c6a5b08.png'
console.log(result(str))
17. 获取指定字符串后的所有字符
let url = 'http://tmp/YdbWDYntvJlucfb97bd5c61696f0b30136b64c6a5b08.png'
let res = url.match(/tmp(\S*)/)[1]
console.log(res)//输出:/YdbWDYntvJlucfb97bd5c61696f0b30136b64c6a5b08.png
18. 按钮显示倒计时文本
this.confirmText = '确定(5s)'
// 清除定时器
this.timer = null
clearTimeout(this.timer)
for (let i = 0; i <= 5; i++) {
this.timer = setTimeout(() => {
if (i < 5) {
this.confirmText = `确定(${5 - i}s)`
} else {
this.confirmText = `确定`
}
}, i * 1000)
}
19. 捕获await函数的try-catch库
await-to-js库,参考文章。
大致流程:函数to接受参数Promise和errorExt,如果这个 Promise 成功时返回[null, data],如果异常时会判断是否带有errorExt参数(代表传递给 err 对象的附加信息),如果有时会与 catch 捕获的 err 合并返回,如果没有时返回[err, undefined]。
1、安装
// use npm
npm i await-to-js --save
// use yarn
yarn add await-to-js
2、使用
import to from 'await-to-js'
// 获取列表list
const [err, data] = await to(getList(params))
if (err) return
通过to函数改造后,如果返回第一个参数不为空时,说明该请求报错,就可以提前 return 出去,如果不存在第一个参数时,则异步请求成功。
20. 如何获取 base URL?
const getBaseURL = (url) => url.replace(/[?#].*$/, '')
getBaseURL('http://url.com/page?name=Adam&surname=Smith')
// 'http://url.com/page'
21. 如何检查 URL 是否为绝对路径?
const isAbsoluteURL = (str) => /^[a-z][a-z0-9+.-]*:/.test(str)
isAbsoluteURL('https://google.com') // true
isAbsoluteURL('ftp://www.myserver.net') // true
isAbsoluteURL('/foo/bar') // false
22. 如何将 URL 参数转换为对象?
const getURLParameters = (url) =>
(url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce(
(a, v) => (
(a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1)), a
),
{}
)
getURLParameters('google.com') // {}
getURLParameters('http://url.com/page?name=Adam&surname=Smith')
// {name: 'Adam', surname: 'Smith'}
23. 如何检查一个元素是否包含另一个元素?
const elementContains = (parent, child) =>
parent !== child && parent.contains(child)
elementContains(document.querySelector('head'), document.querySelector('title'))
// true
elementContains(document.querySelector('body'), document.querySelector('body'))
// false
24. 如何获取元素的所有祖先元素?
const getAncestors = (el) => {
let ancestors = []
while (el) {
ancestors.unshift(el)
el = el.parentNode
}
return ancestors
}
getAncestors(document.querySelector('nav'))
// [document, html, body, header, nav]
25. 如何获取元素的所有祖先元素?
const smoothScroll = (element) =>
document.querySelector(element).scrollIntoView({
behavior: 'smooth',
})
smoothScroll('#fooBar') // 平滑滚动到id为fooBar的元素
smoothScroll('.fooBar')
// 平滑滚动到class为fooBar的第一个元素
26. 如何处理点击元素外部的事件?
const onClickOutside = (element, callback) => {
document.addEventListener('click', (e) => {
if (!element.contains(e.target)) callback()
})
}
onClickOutside('#my-element', () => console.log('Hello'))
// 当用户点击#my-element外部时将输出'Hello'
27. 如何生成 UUID?
const UUIDGeneratorBrowser = () =>
([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
(
c ^
(crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))
).toString(16)
)
UUIDGeneratorBrowser() // '7982fcfe-5721-4632-bede-6000885be57d'
28. 如何获取选定的文本?
const getSelectedText = () => window.getSelection().toString()
getSelectedText() // 'Lorem ipsum'
29. 如何将文本复制到剪贴板?
const copyToClipboard = (str) => {
if (navigator && navigator.clipboard && navigator.clipboard.writeText)
return navigator.clipboard.writeText(str)
return Promise.reject('The Clipboard API is not available.')
}
30. 如何切换全屏模式?
const fullscreen = (mode = true, el = 'body') =>
mode
? document.querySelector(el).requestFullscreen()
: document.exitFullscreen()
fullscreen() // 将body以全屏模式打开
fullscreen(false) // 退出全屏模式
31. 如何检查日期是否有效?
const isDateValid = (...val) => !Number.isNaN(new Date(...val).valueOf())
isDateValid('December 17, 1995 03:24:00') // true
isDateValid('1995-12-17T03:24:00') // true
isDateValid('1995-12-17 T03:24:00') // false
isDateValid('Duck') // false
isDateValid(1995, 11, 17) // true
isDateValid(1995, 11, 17, 'Duck') // false
isDateValid({}) // false
32. 如何从日期获取时间(带冒号)?
const getColonTimeFromDate = (date) => date.toTimeString().slice(0, 8)
getColonTimeFromDate(new Date()) // '08:38:00'
33. 如何从日期生成 UNIX 时间戳?
const getTimestamp = (date = new Date()) => Math.floor(date.getTime() / 1000)
getTimestamp() // 1602162242
34. at()方法获取数组最后一位值
// 获取arr的最后一位值
const arr = [1, 2, 3, 4, 5]
// 一般写法
const last = arr[arr.length - 1]
// 二般写法
const last = arr.slice(-1)[0]
// 终极写法
const last = arr.at(-1)
35. 输入框输入小写自动转大写
<el-input :value="form.trailerNo" @input="(e) => { form.trailerNo = e.toUpperCase().replace(/^\s+|\s+$/g, '') }" clearable placeholder="请输入" />
@input="(e) => { form.trailerNo = e.toUpperCase().replace(/^\s+|\s+$/g, '') }"
36. 深拷贝
/**
* @description 深度克隆
* @param {object} obj 需要深度克隆的对象
* @param cache 缓存
* @returns {*} 克隆后的对象或者原值(不是对象)
*/
export function deepClone(obj, cache = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (cache.has(obj)) return cache.get(obj);
let clone;
if (obj instanceof Date) {
clone = new Date(obj.getTime());
} else if (obj instanceof RegExp) {
clone = new RegExp(obj);
} else if (obj instanceof Map) {
clone = new Map(Array.from(obj, ([key, value]) => [key, deepClone(value, cache)]));
} else if (obj instanceof Set) {
clone = new Set(Array.from(obj, value => deepClone(value, cache)));
} else if (Array.isArray(obj)) {
clone = obj.map(value => deepClone(value, cache));
} else if (Object.prototype.toString.call(obj) === '[object Object]') {
clone = Object.create(Object.getPrototypeOf(obj));
cache.set(obj, clone);
for (const [key, value] of Object.entries(obj)) {
clone[key] = deepClone(value, cache);
}
} else {
clone = Object.assign({}, obj);
}
cache.set(obj, clone);
return clone;
}
36. 位运算
现代计算机中数据都是以二进制的形式存储的,即0、1两种状态,计算机对二进制数据进行的运算加减乘除等都是叫位运算,即将符号位共同参与运算的运算。
常见的位运算有以下几种:
| 运算符 | 描述 | 运算规则 | |
|---|---|---|---|
& | 与 | 两个位都为1时,结果才为1 | |
| ` | ` | 或 | 两个位都为0时,结果才为0 |
^ | 异或 | 两个位相同为0,相异为1 | |
~ | 取反 | 0变1,1变0 | |
<< | 左移 | 各二进制位全部左移若干位,高位丢弃,低位补0 | |
>> | 右移 | 各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃 |
1. 按位与运算符(&)
定义: 参加运算的两个数据按二进制位进行“与”运算。 运算规则:
javascript
代码解读
复制代码
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1
总结:两位同时为1,结果才为1,否则结果为0。 例如:3&5 即:
javascript
代码解读
复制代码
0000 0011
0000 0101
= 0000 0001
因此 3&5 的值为1。 注意:负数按补码形式参加按位与运算。
用途:
(1)判断奇偶
只要根据最未位是0还是1来决定,为0就是偶数,为1就是奇数。因此可以用if ((i & 1) == 0)代替if (i % 2 == 0)来判断a是不是偶数。
(2)清零
如果想将一个单元清零,即使其全部二进制位为0,只要与一个各位都为零的数值相与,结果为零。
2. 按位或运算符(|)
定义: 参加运算的两个对象按二进制位进行“或”运算。
运算规则:
javascript
代码解读
复制代码
0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1
总结:参加运算的两个对象只要有一个为1,其值为1。 例如:3|5即:
javascript
代码解读
复制代码
0000 0011
0000 0101
= 0000 0111
因此,3|5的值为7。 注意:负数按补码形式参加按位或运算。
3. 异或运算符(^)
定义: 参加运算的两个数据按二进制位进行“异或”运算。
运算规则:
javascript
代码解读
复制代码
0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0
总结:参加运算的两个对象,如果两个相应位相同为0,相异为1。 例如:3|5即:
javascript
代码解读
复制代码
0000 0011
0000 0101
= 0000 0110
因此,3^5的值为6。 异或运算的性质:
- 交换律:
(a^b)^c == a^(b^c) - 结合律:
(a + b)^c == a^b + b^c - 对于任何数x,都有
x^x=0,x^0=x - 自反性:
a^b^b=a^0=a;
4. 取反运算符 (~)
定义: 参加运算的一个数据按二进制进行“取反”运算。
运算规则:
javascript
代码解读
复制代码
~ 1 = 0~ 0 = 1
总结:对一个二进制数按位取反,即将0变1,1变0。 例如:~6 即:
javascript
代码解读
复制代码
0000 0110= 1111 1001
在计算机中,正数用原码表示,负数使用补码存储,首先看最高位,最高位1表示负数,0表示正数。此计算机二进制码为负数,最高位为符号位。 当发现按位取反为负数时,就直接取其补码,变为十进制:
javascript
代码解读
复制代码
0000 0110 = 1111 1001反码:1000 0110补码:1000 0111
因此,~6的值为-7。
5. 左移运算符(<<)
定义: 将一个运算对象的各二进制位全部左移若干位,左边的二进制位丢弃,右边补0。 设 a=1010 1110,a = a<< 2 将a的二进制位左移2位、右补0,即得a=1011 1000。 若左移时舍弃的高位不包含1,则每左移一位,相当于该数乘以2。
6. 右移运算符(>>)
定义: 将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。 例如:a=a>>2 将a的二进制位右移2位,左补0 或者 左补1得看被移数是正还是负。 操作数每右移一位,相当于该数除以2。
7. 原码、补码、反码
上面提到了补码、反码等知识,这里就补充一下。 计算机中的有符号数有三种表示方法,即原码、反码和补码。三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位,三种表示方法各不相同。
(1)原码
原码就是一个数的二进制数。例如:10的原码为0000 1010
(2)反码
- 正数的反码与原码相同,如:10 反码为 0000 1010
- 负数的反码为除符号位,按位取反,即0变1,1变0。
例如:-10
javascript
代码解读
复制代码
原码:1000 1010
反码:1111 0101
(3)补码
- 正数的补码与原码相同,如:10 补码为 0000 1010
- 负数的补码是原码除符号位外的所有位取反即0变1,1变0,然后加1,也就是反码加1。
例如:-10
javascript
代码解读
复制代码
原码:1000 1010
反码:1111 0101
补码:1111 0110
作者:CUGGZ
链接:juejin.cn/post/694094…
37. 邮箱正则表达式
- 简单版本的邮箱正则表达式
/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
- 编写一个支持 Unicode 字符集的电子邮箱正则表达式,我们需要确保正则表达式能够匹配包含非 ASCII 字符的邮箱地址。这通常用于支持国际化的邮箱地址,例如包含中文、日文、西班牙文、葡萄牙文等语言的字符。
标准的电子邮件地址格式允许使用国际化域名(IDN),但本地部分(@ 符号之前的部分)通常仍然限制为 ASCII 字符。为了支持 Unicode 字符集,我们需要扩展正则表达式以支持国际化域名。
以下是一个支持 Unicode 字符集的电子邮箱正则表达式示例:
/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}|\p{L}+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/u
- 然而,JavaScript 的正则表达式引擎对 Unicode 的支持有限,特别是对于完整的国际化域名。为了更好地支持国际化域名,可以使用更复杂的正则表达式或第三方库。以下是一个更复杂的正则表达式示例,用于支持国际化域名:
/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}|\p{L}+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}|\p{L}+@[a-zA-Z0-9.-]+\.[a-zA-Z\u00C0-\u024F\u0370-\u03FF\u0400-\u04FF\u0530-\u058F\u0590-\u05FF\u0600-\u06FF\u0700-\u074F\u0780-\u07BF\u0800-\u083F\u0840-\u085F\u08A0-\u08FF\u0900-\u097F\u0980-\u09FF\u0A00-\u0A7F\u0A80-\u0AFF\u0B00-\u0B7F\u0B80-\u0BFF\u0C00-\u0C7F\u0C80-\u0CFF\u0D00-\u0D7F\u0D80-\u0DFF\u0E00-\u0E7F\u0E80-\u0EFF\u0F00-\u0FFF\u1000-\u109F\u10A0-\u10FF\u1100-\u11FF\u1200-\u124F\u1250-\u127F\u1280-\u12BF\u12C0-\u12DF\u1300-\u134F\u13A0-\u13FF\u1400-\u167F\u1680-\u169F\u16A0-\u16FF\u1700-\u171F\u1720-\u173F\u1740-\u175F\u1760-\u177F\u1780-\u17FF\u1800-\u18AF\u1900-\u194F\u1950-\u197F\u1980-\u19DF\u19E0-\u19FF\u1A00-\u1A1F\u1A20-\u1AAF\u1B00-\u1B7F\u1B80-\u1BBF\u1BC0-\u1BFF\u1C00-\u1C4F\u1C50-\u1C7F\u1CD0-\u1CFF\u1D00-\u1D7F\u1D80-\u1DBF\u1DC0-\u1DFF\u1E00-\u1EFF\u1F00-\u1FFF\u2000-\u206F\u2070-\u209F\u20A0-\u20CF\u2100-\u214F\u2150-\u218F\u2190-\u21FF\u2200-\u22FF\u2300-\u23FF\u2400-\u243F\u2440-\u245F\u2460-\u24FF\u2500-\u257F\u2580-\u259F\u25A0-\u25FF\u2600-\u26FF\u2700-\u27BF\u2800-\u28FF\u2A00-\u2AFF\u2B00-\u2BFF\u2C00-\u2C5F\u2C60-\u2C7F\u2C80-\u2CFF\u2D00-\u2D2F\u2D30-\u2D7F\u2D80-\u2DBF\u2DC0-\u2DFF\u2E00-\u2E7F\u2F00-\u2FDF\u3000-\u303F\u3040-\u309F\u30A0-\u30FF\u3100-\u312F\u3130-\u318F\u3190-\u319F\u31A0-\u31BF\u3200-\u32FF\u3300-\u33FF\u3400-\u4DBF\u4DC0-\u4DFF\u4E00-\u9FFF\uA000-\uA48F\uA490-\uA4CF\uA500-\uA63F\uA640-\uA69F\uA6A0-\uA6FF\uA700-\uA71F\uA720-\uA7FF\uA800-\uA82F\uA840-\uA87F\uA880-\uA8DF\uA900-\uA92F\uA930-\uA95F\uA960-\uA97F\uA980-\uA9DF\uA9E0-\uA9FF\uAA00-\uAA5F\uAA60-\uAA7F\uAA80-\uAADF\uAAE0-\uAAFF\uAB00-\uAB2F\uAB30-\uAB6F\uAB70-\uABBF\uABC0-\uABFF\uD800-\uD83F\uD840-\uD87F\uD880-\uD8BF\uD900-\uD93F\uD940-\uD97F\uD980-\uD9BF\uD9C0-\uD9FF\uDA00-\uDA3F\uDA40-\uDA6F\uDA70-\uDA9F\uDA80-\uDADF\uDB00-\uDB7F\uDB80-\uDBBF\uDC00-\uDC7F\uDC80-\uDCFF\uDD00-\uDD4F\uDD50-\uDD7F\uDD80-\uDDDF\uDE00-\uDE4F\uDE50-\uDE7F\uDE80-\uDE9F\uDEA0-\uDECF\uDEE0-\uDEF8\uDF00-\uDF3F\uDF40-\uDF5F\uDF60-\uDF7F\uDF80-\uDF9F\uDFA0-\uDFBF\uDFC0-\uDFDF\uDFF0-\uDFFF]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/u
38. window.atob&window.btoa
btoa()将二进制字符串(普通字符串)转为Base64编码的ASCII字符串atob()将Base64编码的ASCII字符串转为二进制字符串(普通字符串)
window.btoa(JSON.stringify({account: 'test', password: '123123'}))
// 输出 'eyJhY2NvdW50IjoidGVzdCIsInBhc3N3b3JkIjoiMTIzMTIzIn0='
window.atob('eyJhY2NvdW50IjoidGVzdCIsInBhc3N3b3JkIjoiMTIzMTIzIn0=')
// 输出 '{"account":"test","password":"123123"}'
39. 只需一行代码,任意网页秒变可编辑
document.designMode = "on";