JS方法速查

2020/8/31 JS

# JS方法速查

此文章是我用过最多的文章,需要进行重构(重构未完成...)

# 🍥第一部分:数组

# 1.数组去重

let arrs = [1,2,2,3,3,6,5,5];

// ES6
[...new Set(arr)] // [1,2,3,6,5]
// 此方法也能去除字符串中重复的项:[...new Set('ababbc')].join('') // abc

// 其他去重方法
function uniq(array){
    let temp = [];
    let l = array.length;
    for(let i = 0; i < l; i++) {
        for(let j = i + 1; j < l; j++){
            if (array[i] === array[j]){
                i++;
                j = i;
            }
        }
        temp.push(array[i]);
    }
    return temp;
}
console.log(uniq(arrs)); // [1,2,3,6,5]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

数组去重拓展(传参数 指定去除哪个重复的,未完成)


# 2.数组合并

let arr1 = [1,2,3]
let arr2 = [4,5,6]

// ES6
[...arr1, ...arr2] // [1, 2, 3, 4, 5, 6]


// 方法2:concat方法(挂载Array原型链上)
let c = a.concat(b);
console.log(c); // [1, 2, 3, 4, 5, 6]
console.log(a); // [1, 2, 3]  不改变本身
// 备注:看似concat似乎是 数组对象的深拷贝,其实,concat 只是对数组的第一层进行深拷贝

// 方法3:apply方法
Array.prototype.push.apply(a, b);
console.log(a); // [1, 2, 3, 4, 5, 6] 改变原目标数组
console.log(b); // [4, 5, 6]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 3.数组排序(sort)

let objArr = [
  {name: 'test1', age: 20},
  {name: 'test1', age: 22},
  {name: 'test1', age: 21}
]

// 第一参数a, 第二参数b ---> a-b升序(从小到大);b-a降序(从大到小),原理就是 两数计算,如果返回的是负数,就保留前者(我可能说的不对,欢迎纠正)
objArr.sort((a, b) => {
  return a.age - b.age
}) 
// 结果会按照年龄从小到大的顺序排列


1
2
3
4
5
6
7
8
9
10
11
12
13

# 4.多维数组转一维数组(flat)

let arr = [1, [2], [[3], 4], 5];

// ES6 数组的flat()
arr.flat() // [1, 2, Array(1), 4, 5] 如果这样写的话只能展开二维数组,但是可以加参数Infinity,就是能展开多维数组
arr.flat(Infinity) // [1, 2, 3, 4, 5] 注意如果原数组有空位,flat()方法会跳过空位

// 其他方法
const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v)));
deepFlatten(arr); // [1,2,3,4,5]


// 执行效率验证(拓展)
// let start = new Date().getTime();
// console.log('reduceDimension: ', deepFlatten([1, [2], [[3], 4], 5]);
// console.log('耗时: ', new Date().getTime() - start); // *ms

// ES6 数组的flatMap() 方法大家可以自行查阅一下,拓展下自己的知识面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 5.过滤数组(filter)

let json = [
  { id: 1, name: 'john', age: 24 },
  { id: 2, name: 'zkp', age: 21 },
  { id: 3, name: 'mike', age: 50 }
];

// ES6
json.filter( item => item.age > 22) // [{id: 1, name: 'john', age: 24}, { id: 3, name: 'mike', age: 50 }]

// ES5

1
2
3
4
5
6
7
8
9
10
11

# 6.判断数组中的项是否满足于某个条件(some,every)

let arr = [4, 2, 3]

// ES6 some方法(有符合)
arr.some( item => item > 1) // true
arr.some( item => item > 3) // true

// ES5 every(全符合)

arr.every(item => item > 1) // true
arr.every(item => item > 3) // false

// 注意:上面两个有不同哦,一个是有符合的判定,一个是全符合的判定
1
2
3
4
5
6
7
8
9
10
11
12

# 7.操作数组中的每一项,并使其按照一定的逻辑返回(map)

var potatos = [
  { id: '1001', weight: 50 },
  { id: '1002', weight: 80 },
  { id: '1003', weight: 120 },
  { id: '1004', weight: 40 }
]

// ES6写法
const fn = (arr, key) => arr.map(arr =>  arr[key])

fn(potatos, 'id') // ["1001", "1002", "1003", "1004"]
fn(potatos, 'weight') // [50, 80, 120, 40]
1
2
3
4
5
6
7
8
9
10
11
12

# 8.其他常用的ES6 Array方法

// forEach() 遍历数组

// pop() 删除数组中最后一个元素,并返回该元素的值。此方法更改数组的长度

// shift() 删除数组中第一个元素,并返回该元素的值。此方法更改数组的长度

// push() 将一个或多个元素添加到数组的末尾,并返回该数组的新长度

// unshift() 将一个或多个元素添加到数组的开头,并返回该数组的新长度(该方法修改原有数组)

// 🔥Array.prototype.filter() 创建一个新数组, 其包含通过所提供函数实现的测试的所有元素,不会改变原有值,如果没符合的返回[]
let arr = [1, 2, 3]
arr.filter( x => x > 1) // [2, 3]

// Array.prototype.join() 将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串
['Fire', 'Air', 'Water'].join() // "Fire,Air,Water"

// Array.prototype.slice() 取出任意元素, | 参数一:从哪开始,参数二(可选)结束位置,不选的话 就节选到最后了
[1, 2, 3].slice(0, 1) // [1]

// Array.prototype.splice() 删除任意元素,操作任意元素 | 参数一:从哪开始 | 参数二:操作元素的个数 | 参数三:插入元素的值...(可以写多个参数三)
[1, 2, 3].splice(0, 1) // 删除 [2, 3]

// Array.prototype.includes() 用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。
[1, 2, 3].includes(1) // true

// Array.prototype.reverse() 颠倒数组
[1, 2, 3].reverse() // [3, 2, 1]

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

点击此处,查看更详细链接 (opens new window)


# 9.获得数组最大最小值


// 使用 Math 中的 max/min 方法
let arr = [22,13,6,55,30];

// ES6
Math.max(...arr); // 55
Math.min(...arr); // 6

// ES5
Math.max.apply(null, arr); // 55
Math.min.apply(null, arr); // 6

1
2
3
4
5
6
7
8
9
10
11
12

# 10.获取数组交集

// ES6 写法
const similarity = (arr1, arr2) => arr1.filter(v => arr2.includes(v));
similarity([1, 2, 3], [1, 2, 4]); // [1,2]

// ES5 写法
// function similarity(arr1, arr2) {
//   return arr2.filter(function(v) {
//     return arr1.includes(v)
//   })
// }
1
2
3
4
5
6
7
8
9
10

# 11.数组对象去重

let arr = [
  {id: 1, name: 'Jhon1'},
  {id: 2, name: 'sss'},
  {id: 3, name: 'Jhon2'},
  {id: 4, name: 'Jhon3'}
]

// ES6
const uniqueElementsBy = (arr, fn) =>arr.reduce((acc, v) => {if (!acc.some(x => fn(v, x))) acc.push(v);return acc;}, []);

// 下面的示例表示,去重依据是 id ,就是 id一样的,只留下一个
uniqueElementsBy(arr, (a, b) => a.id === b.id) // [{id: 1, name: 'Jhon1'}, {id: 2, name: 'sss'}]

1
2
3
4
5
6
7
8
9
10
11
12
13

# 12.数组乱序

function shuffle(arr) {
  let array = arr
  let index = array.length

  while (index) {
    index -= 1
    let randomInedx = Math.floor(Math.random() * index)
    let middleware = array[index]
    array[index] = array[randomInedx]
    array[randomInedx] = middleware
  }

  return array
}

let arr = [1,2,3,4,5]
shuffle(arr) // [3, 4, 2, 5, 1] 结果不定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

还有更简单的方式,欢迎来撩


# 13.检查数组中某元素出现的次数

function countOccurrences(arr, value) {
  return arr.reduce((a, v) => v === value ? a + 1 : a + 0, 0);
}

let arr = [1,2,3,4,1,2,4]
countOccurrences(arr, 1) // 2
1
2
3
4
5
6

# 14.检查数组中的所有元素是否相等

const allEqual = arr => arr.every(val => val === arr[0]);

// 示例
allEqual([1, 2, 3, 4, 5, 6]); // false
allEqual([1, 1, 1, 1]); // true
1
2
3
4
5

# 15.数组对象,求某一列属性的总和

var potatos = [
  { id: '1001', weight: 50 },
  { id: '1002', weight: 80 },
  { id: '1003', weight: 120 },
  { id: '1004', weight: 40 }
]

// ES6写法
const fn = (arr, key) => arr.reduce((sum, p) => { return p[key] + sum },0)

fn(potatos, 'weight') // 290
fn(potatos, 'id') // "10041003100210010" 字符串相加就是这个结果,如果有各自的需求,可以自己加上
1
2
3
4
5
6
7
8
9
10
11
12

# 16.分割数组,并操作数组每一项(函数)

/**
 * 数组分隔方法,并且可以传入一个处理函数,用来分隔之前处理数组的每一项
 * 
 * @category Array
 * @param {Array} array 需要处理的数组
 * @param {number} [size = 1] 每个数组区块的长度
 * @param {Function} [fn = item => item] 函数
 * @returns {Array} 返回一个包含拆分区块的新数组(相当于一个二维数组)。
 * @example
 *
 * chunk(['a', 'b', 'c', 'd'], 2)
 * // => [['a', 'b'], ['c', 'd']]
 *
 * chunk(['a', 'b', 'c', 'd'], 3)
 * // => [['a', 'b', 'c'], ['d']]
 *
 * chunk([1, 2, 3, 4], 3, item => item * 2)
 * // => [[2, 4, 6], [8]]
 */

function chunk(array, size = 1, fn = item => item) {
    
    array = array.map(fn)

    size = Math.max(size, 0) // 这一句就很妙,当传入值小于0的时候,置为0,大于0的时候,不写,但不知道性能怎么样
    const length = array == null ? 0 : array.length
    if (!length || size < 1) {
      return []
    }
    let index = 0
    let resIndex = 0
    const result = new Array(Math.ceil(length / size))
  
    while (index < length) {
      result[resIndex++] = array.slice(index, (index += size))
    }
    return result
}
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

# 17.数组分页算法

data.slice([每页数据量 *(当前页码 - 1, 每页数据量 *(当前页码 - 1+ 每页数据量])
1


# 🍡第二部分:对象

# 1.对象合并


// 1️⃣ ES6方法

let obj1 = {
    a:1,
    b:{ 
        b1:2 
    }
}

let obj2 = { c:3, d:4 }

console.log({...obj1, ...obj2}) // {a: 1, b: {…}, c: 3, d: 4}
// 支持无限制合并,但如果对象之间存在相同属性,则后面属性会覆盖前面属性。*请注意,这仅适用于浅层合并。


// 2️⃣ Obj.assign():可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象
let o1 = { a: 1 };
let o2 = { b: 2 };

let obj = Object.assign(o1, o2);
console.log(obj); // { a: 1, b: 2 }
console.log(o1);  // { a: 1, b: 2 }, 且 **目标对象** 自身也会改变(也就是assign第一个对象)
console.log(o2); // { b: 2 } 不改变

// 备注:Object.assign() 拷贝的是属性值。假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值
// 备注:数组合并用 concat() 方法


// 3️⃣ $.extend()

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

# 2.浅拷贝,深拷贝

深拷贝(基础版)


/**
 * 此函数,可以完全生成一个新的拷贝对象,也可以将一个对象中的属性拷贝到另一个对象中去
 * @parmas {Object} 需要被拷贝的对象
 * @parmas {Object} 可选,目标对象,如果不填直接返回一个对象
 */

function deepClone(origin, target = {}) {

    // 循环遍历对象的属性
    for (key in origin) {
        
        let isType = Object.prototype.toString.call(origin[key])

        // 克隆对象类型
        if (isType === '[object Object]') {
            target[key] = {}
            deepClone(origin[key], target[key])
            continue
        }

        // 克隆数组类型
         if (isType === '[object Array]') {
            target[key] = []
            deepClone(origin[key], target[key])
            continue
        }

        // 克隆 Set 类型
      
        // 克隆 Map 类型

        // 克隆其他类型

        // 克隆基础类型
        target[key] = origin[key]
    
    }

    return target
}

let zhu = {
  name: '柠栀',
  technology: ['css', 'html', 'js'],
  girlfriend: {
    name: 'lyt'
  }
}

let zhuClone = deepClone(zhu) // zhuClone 内容完全和 zhu 一样

let zhuTest = { test: '测试' }
let zhuTestClone = deepClone(zhuTest, zhu) // zhuTestClone 不仅有 zhu所有内容,还有 zhuTest 的内容



// JSON.parse(JSON.stringify(obj) 方法进行拷贝,了解就行
const obj = {
  name:'axuebin',
  sayHello:function(){
    console.log('Hello World');
  }
}
console.log(JSON.parse(JSON.stringify(obj)); // {name: "axuebin"} ???
// undefined、function、symbol 会在转换过程中被忽略,所以就不能用这个方法进行深拷贝


// 浅拷贝
function clone(origin, target = {}) {
    let target = {};
    for (const key in origin) {
        target[key] = origin[key];
    }
    return target;
};

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

# 3.拓展:首层浅拷贝


function shallowClone(source) {
  const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象
  for (let keys in source) { // 遍历目标
    if (source.hasOwnProperty(keys)) {
      targetObj[keys] = source[keys];
    }
  }
  return targetObj;
}

const originObj = {
  a:'a',
  b:'b',
  c:[1, 2, 3],
  d:{ dd: 'dd' }
};

const cloneObj = shallowClone(originObj);
console.log(cloneObj === originObj); // false
cloneObj.a = 'aa';
cloneObj.c = [1, 1, 1];
cloneObj.d.dd = 'surprise';

console.log(cloneObj); // {a:'aa',b:'b',c:[1,1,1],d:{dd:'surprise'}}
console.log(originObj); // {a:'a',b:'b',c:[1,2,3],d:{dd:'surprise'}}

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

# 4.判断对象是否为空对象


// 参考:https://www.cnblogs.com/HKCC/p/6083575.html

if (JSON.stringify(对象) === '{}') {
  console.log('空');
}

1
2
3
4
5
6
7

# 5.判断对象中属性的个数

let obj = {name: '柠栀', age: 21}

// ES6
Object.keys(obj).length // 2

// ES5
let attributeCount = obj => {
    let count = 0;
    for(let i in obj) {
        if(obj.hasOwnProperty(i)) {  // 建议加上判断,如果没有扩展对象属性可以不加
            count++;
        }
    }
    return count;
}

attributeCount(obj) // 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 6.JS 对象转 url 查询字符串

const objectToQueryString = (obj) => Object.keys(obj).map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`).join('&');
objectToQueryString({name: 'Jhon', age: 18, address: 'beijing'})
// name=Jhon&age=18&address=beijing
1
2
3

# 7.对象遍历

let objs = {
    1: {
        name: '柠栀'
    },
    2: {
        name: '林雨桐'
    }
}

Object.keys(objs).forEach( ket => {
  console.log(key,objs[key])
})

// 1 {name: '柠栀'} 2 {nama:'林雨桐'}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 8.字符串与对象相互转换

链接 (opens new window)


# 🍧第三部分:DOM


# 1.常用DOM接口


// 获取DOM节点
document.getElementById() // 通过ID获取
document.getElementsByTagName() // 标签名
document.getElementsByClassName() // 类名
document.querySelector() // 通过选择器获取一个元素
document.querySelectorAll() // 通过选择器获取一组元素
document.body // 获取body的方法
document.getElementsByName(name) // 通过name属性查找元素节点
document.documentElement // 获取html的方法

// 节点类型
元素节点(标签) // 属性nodeType返回值1
属性节点(标签里的属性)// 返回值2
文本节点 // 返回值3
注释节点(comment) // 返回值8
document // 返回值9
DocumentFragment // 返回值11

// 节点接口
dom元素.parentNode // 返回当前元素的父节点
dom元素.childNodes // 子节点们
dom元素.firstChild // 第一个子节点
dom元素.lastChild // 最后一个子节点
dom元素.nextSibling // 后一个兄弟节点 previousSibling -> 前一个兄弟节点

// 元素节点接口
dom元素.parentElement // 返回当前元素的父元素节点
dom元素.children // 返回当前元素的元素子节点
dom元素.firstElementChild // 第一个元素子节点(IE不兼容)
dom元素.lastElementChild // 最后一个元素子节点(IE不兼容)
dom元素.nextElementSibling // 返回后一个兄弟元素节点
dom元素.previousElementSibling // 返回前一个兄弟元素节点

// 节点的四个属性和一个方法
节点.nodeName // 元素的标签名,以大写形式表示(只读)
节点.nodeValue // Text节点或者Comment节点的文本内容,(读写)
节点.nodeType // 该节点的类型(只读)
节点.attributes // Element节点的属性集合
节点.hasChildNodes() // 判断节点 是否有子节点

// Element节点的 属性和方法
dom元素.innerHtml
dom元素.innerText
dom元素.attributes // 获取元素身上所有属性构成的集合
dom元素.setAttribute("属性名","属性值")// 给元素设置属性和属性值
dom元素.getAttribute("属性名")// 获取属性值的方法
dom元素.removerAttribute("属性") // 删除属性


// ============== 操作接口 ==================

// 增
document.createElement() // 创建元素节点
document.createTextNode() // 创建文本节点
document.creaetComment() //创建注释节点
document.createDocumentFragment() // 创建文档碎片节点

// 插
父元素节点.appendChild(子元素对象) // 在元素节点的子元素最后插入子元素
父元素节点.insertBefore(父元素中的子元素a, 需要插入的子元素b) // 最后的结果是,父元素节点中 b元素插入到了 a的前面


// 删
元素节点.remove() // 删除DOM元素(自己)
父元素节点.removeChild(子元素节点) // 删除子元素

// 替换
父元素节点.replaceChild(新的节点, 需要被替换的子节点)

// 复制
元素节点.cloneChild() // 返回值是 复制出来的节点

// 查看滚动条的滚动距离
window.pageXOffset // x轴滚动距离
window.pageYOffset // y轴滚动距离
document.body.scrollLeft // x轴滚动距离(兼容低版本IE)
document.body.scrollTop // y轴滚动距离(兼容低版本IE)
// 如何兼容,因为如果有 pageXOffset,那么另一个兼容性的结果就是0,所以相加就能解决兼容性问题了

// 让滚动条滚动
window.scroll(x, y) // 滚动到某个位置
window.scrollTo(x, y) // 滚动到某个位置
window.scrollBy(x, y) // 累加滚动,就是每执行一次,就滚动多少位置

// 查看视口的尺寸
window.innerWidth // 视口的宽度
window.innerHeight // 视口的高度
document.documentElement.clientWidth // 兼容低版本IE
document.documentElement.clientHeight // 兼容低版本IE
document.body.clientWidth // 兼容怪异模式
document.body.clientHeight //兼容怪异模式
document.compatMode // 查看渲染模式 | 'CSS1Compat' 标准模式 | 'BackCompat' 怪异模式

// 查看元素的几何尺寸
dom元素.offsetWidth // 元素的宽度
dom元素.offsetHeight // 元素的高度
dom元素.offsetLeft // 元素相当于父级的位置(如果父级有定位的话,如果没有就是相对于文档的距离)
dom元素.offsetTop // 元素相对于父级的位置(如果父级有定位的话,如果没有就是相对于文档的距离)
dom元素.offsetParent // 返回最近有定位的父级DOM节点

// 脚本化css
dom元素.style // 查看所有样式表接口(内容可读可写)
dom元素.style. = ... // 碰到float这样的保留字,前面加css,例如 cssFloat
dom元素.style.width = ...
dom元素.style.backgroundColor = ...
dom元素.className = ...

window.getComputedStyle(ele, null) // 返回某个元素,最后展示效果的 样式表对象(CSSStyleDeclaration)| 只读 | IE8以下不兼容

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
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
99
100
101
102
103
104
105
106
107
108
109
110

# 2.判断当前位置是否为页面底部

function bottomVisible() {
  return document.documentElement.clientHeight + window.scrollY >= (document.documentElement.scrollHeight || document.documentElement.clientHeight)
}

bottomVisible() // 返回值为true/false
1
2
3
4
5

# 3.全屏

# 1.进入全屏
function launchFullscreen(element) {
  if (element.requestFullscreen) {
    element.requestFullscreen()
  } else if (element.mozRequestFullScreen) {
    element.mozRequestFullScreen()
  } else if (element.msRequestFullscreen) {
    element.msRequestFullscreen()
  } else if (element.webkitRequestFullscreen) {
    element.webkitRequestFullScreen()
  }
}

launchFullscreen(document.documentElement) // 整个页面进入全屏
launchFullscreen(document.getElementById("id")) //某个元素进入全屏
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 退出全屏
function exitFullscreen() {
  if (document.exitFullscreen) {
    document.exitFullscreen()
  } else if (document.msExitFullscreen) {
    document.msExitFullscreen()
  } else if (document.mozCancelFullScreen) {
    document.mozCancelFullScreen()
  } else if (document.webkitExitFullscreen) {
    document.webkitExitFullscreen()
  }
}

exitFullscreen()
1
2
3
4
5
6
7
8
9
10
11
12
13
# 全屏事件
document.addEventListener("fullscreenchange", function (e) {
  if (document.fullscreenElement) {
    console.log('进入全屏')
  } else {
    console.log('退出全屏')
  }
})
1
2
3
4
5
6
7

# 4.判断dom元素是否具有某个className

方法一:使用HTML5新增classList 来操作类名

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="test" class="te"></div>

  <script>
    
    let div = document.getElementById('test')
    console.log(div.classList.contains("te")) // true

  </script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

拓展:

  • classList.add(newClassName);添加新的类名,如已经存在,取消添加
  • classList.contains(oldClassName):确定元素中是否包含指定的类名,返回值为true,false
  • classList.remove(oldClassName):移除已经存在的类名;
  • classList.toggle(className):如果classList中存在给定的值,删除它,否则,添加它;

🦀感谢掘金用户tjNane分享此方法


方法二:

const  hasClass = (el, className) => new RegExp(`(^|\\s)${className}(\\s|$)`).test(el.className);
1

# 5.返回某元素的第n层祖先元素节点

function retParent(ele, n) {
    
    while(elem && n) {
        ele = ele.parentElement
        n--
    }

    return ele
}
1
2
3
4
5
6
7
8
9

# 6.滚动到底部监听函数

function bottomMonitorEvent(dom) {
    const prizeRecordRoll = dom;
    prizeRecordRoll.onscroll = () => {
        const scrollTop = prizeRecordRoll.scrollTop;
        const windowHeight = prizeRecordRoll.clientHeight;
        const scrollHeight = prizeRecordRoll.scrollHeight;

        if (Math.floor(scrollTop + windowHeight - scrollHeight) >= -1) {
            // 到底事件触发,书写业务逻辑
        }

    };
},
1
2
3
4
5
6
7
8
9
10
11
12
13

# 🍣第四部分:BOM

# 1.返回当前网页地址

function currentURL() {
  return window.location.href
}

currentURL() // "https://juejin.im/timeline"
1
2
3
4
5

# 2.获取滚动条位置

function getScrollPosition(el = window) {
  return {
    x: (el.pageXOffset !== undefined) ? el.pageXOffset : el.scrollLeft,
    y: (el.pageYOffset !== undefined) ? el.pageYOffset : el.scrollTop
  }
}

getScrollPosition() // {x: 0, y: 692}
1
2
3
4
5
6
7
8

# 3.获取url中的参数

function getURLParameters(url) {
  const params = url.match(/([^?=&]+)(=([^&]*))/g)
  return params?params.reduce(
    (a, v) => (a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1), a), {}
  ):[]
}

getURLParameters('http://www.baidu.com/index?name=tyler') // {name: "tyler"}
1
2
3
4
5
6
7
8

# 4.检测设备类型

const detectDeviceType = () =>/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|OperaMini/i.test(navigator.userAgent) ? 'Mobile' : 'Desktop';

detectDeviceType() // "Desktop"
1
2
3

# 🍬第五部分:时间

# 1.Date 常用API

new Date() // 创建一个时间对象 Fri Jul 12 2019 19:59:59 GMT+0800 (中国标准时间)

// 返回自1970年1月1日 00:00:00 UTC到当前时间的毫秒数。
Date.now(); // 1562932828164

// 解析一个表示某个日期的字符串,并返回从1970-1-1 00:00:00 UTC 到该日期对象(该日期对象的UTC时间)的毫秒数
Date.parse('2019.7.12') // 1562860800000

// 年月日时分秒 获取
let dateMe = new Date()

dateMe.getFullYear() // 2019 | 根据本地时间返回指定日期的年份
dateMe.getMonth() // 6 | 根据本地时间,返回一个指定的日期对象的月份,为基于0的值(0表示一年中的第一月)。
dateMe.getDate() // 12 | 根据本地时间,返回一个指定的日期对象为一个月中的哪一日(从1--31)
dateMe.getHours() // 20 |根据本地时间,返回一个指定的日期对象的小时。
dateMe.getMinutes() // 11 | 根据本地时间,返回一个指定的日期对象的分钟数。
dateMe.getSeconds() // 29 | 方法根据本地时间,返回一个指定的日期对象的秒数
dateMe.getMilliseconds() // 363 | 根据本地时间,返回一个指定的日期对象的毫秒数。

dateMe.toJSON() // 🔥 "2019-07-12T12:05:15.363Z" | 返回 Date 对象的字符串形式
dateMe.getDay() // 5 | 根据本地时间,返回一个具体日期中一周的第几天,0 表示星期天(0 - 6)
dateMe.getTime() // 1562933115363 | 方法返回一个时间的格林威治时间数值。
dateMe.toString() // "Fri Jul 12 2019 20:05:15 GMT+0800 (中国标准时间)" | 返回一个字符串,表示该Date对象
dateMe.getTimezoneOffset() // -480(说明比正常时区慢480分钟,所以要加480分钟才对) | 返回协调世界时(UTC)相对于当前时区的时间差值,单位为分钟。
dateMe.toDateString() // "Fri Jul 12 2019" | 以美式英语和人类易读的形式返回一个日期对象日期部分的字符串。

// 时间戳转当前北京时间(非常的好用)
const startMe = new Date(Date.now());
const toLocale = startMe.toLocaleDateString().replace(/\//g, '-') // 2019-11-20
const toTime = startMe.toTimeString().split(' ')[0] // 00:16:26
const theTime =  `${toLocale} ${toTime}` // 2019-11-20 00:16:26

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

MDN 更多详细 (opens new window)


# 2.一个时间戳格式的数字,是多少 天小时分钟秒毫秒

const formatDuration = ms => {
  if (ms < 0) ms = -ms;
  const time = {
    day: Math.floor(ms / 86400000),
    hour: Math.floor(ms / 3600000) % 24,
    minute: Math.floor(ms / 60000) % 60,
    second: Math.floor(ms / 1000) % 60,
    millisecond: Math.floor(ms) % 1000
  };
  return Object.entries(time)
    .filter(val => val[1] !== 0)
    .map(([key, val]) => `${val} ${key}${val !== 1 ? 's' : ''}`)
    .join(', ');
};

formatDuration(3161012); // 52 minutes, 41 seconds, 12 milliseconds
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 3.格林尼治时间 转 北京时间(可传格林尼治时间 或者 时间戳)

function myTimeToLocal(inputTime){
	if(!inputTime && typeof inputTime !== 'number'){
		return '';
	}
	let localTime = '';
	inputTime = new Date(inputTime).getTime();
	const offset = (new Date()).getTimezoneOffset();
	localTime = (new Date(inputTime - offset * 60000)).toISOString();
	localTime = localTime.substr(0, localTime.lastIndexOf('.'));
	localTime = localTime.replace('T', ' ');
	return localTime;
}

console.log(myTimeToLocal(1530540726443)); // 2018-07-02 22:12:06
console.log(myTimeToLocal('2017-11-16T05:23:20.000Z')); // 2017-11-16 13:23:20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 4.获取两个日期相差天数

function getDaysDiffBetweenDates (dateInitial, dateFinal) {
    return (dateFinal - dateInitial) / (1000 * 3600 * 24);
}

getDaysDiffBetweenDates(new Date('2017-12-13'), new Date('2017-12-22')); // 9
1
2
3
4
5

# 5.一个数组中,有时间,需要将这个数组按照时间进行排序

let data = [
{
  id: 1,
  publishTime: "2019-05-14 18:10:29"
},
{
  id: 2,
  publishTime: "2019-05-14 18:17:29"
},
{
  id: 3,
  publishTime: "2019-05-14 15:09:25"
}]

data.sort((a, b) => b.publishTime - a.publishTime);

// 0: {id: 2, publishTime: "2019-05-14 18:17:29"}
// 1: {id: 1, publishTime: "2019-05-14 18:10:29"}
// 2: {id: 3, publishTime: "2019-05-14 15:09:25"}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 6.iOS 手机时间格式出现NaN的问题

let time = '2019-05-14 18:17:29'
var timeArr = time.split(/[- :]/); // ["2019", "05", "14", "18", "17", "29"]
var resTime = new Date(timeArr[0], timeArr[1] - 1, timeArr[2], timeArr[3], timeArr[4], timeArr[5]);
1
2
3

# 7.判断时间是否到了(兼容性IOS NaN问题)

/*
 * @param { String|Number } 开始时间
 * @param { String|Number } 结束时间
 * @return { Boolean } 时间是否到了
 * @start-time 2019-12-24 18:00
 * @last-time 2019-12-24 18:00
*/
function isJudgeTimeTool(startTime, endTime) {
    
    let nowTime = null;
    let endTimeData = null;

    // 开始时间
    if (typeof startTime === 'number') {
        nowTime = new Date(startTime);
    } else {
        const arr = startTime.split(/[- :]/);
        nowTime = new Date(arr[0], arr[1] - 1, arr[2], arr[3], arr[4], arr[5]);
    }

    // 结束时间
    if (typeof endTime === 'number') {
        endTimeData = new Date(endTime);
    } else {
        const arr = endTime.split(/[- :]/);
        endTimeData = new Date(arr[0], arr[1] - 1, arr[2], arr[3], arr[4], arr[5]);
    }

    // 相差时间
    const leftTime = parseInt((endTimeData.getTime() -nowTime.getTime()) / 1000);

    return leftTime > 0;
}
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

# 🍭第六部分:处理JS原生具有的一些问题

# 1.加减法精度缺失问题

// 加法函数(因为JS小数计算 丢失精度)
function add(arg1, arg2) { 
    let r1, r2, m; 
    try { r1 = arg1.toString().split(".")[1].length } catch (e) { r1 = 0 } 
    try { r2 = arg2.toString().split(".")[1].length } catch (e) { r2 = 0 } 
    m = Math.pow(10, Math.max(r1, r2)) 
    return (arg1 * m + arg2 * m) / m 
}
1
2
3
4
5
6
7
8
// 减法函数(因为JS小数计算 丢失精度)
function sub(arg1, arg2) { 
    let r1, r2, m, n; 
    try { r1 = arg1.toString().split(".")[1].length } catch (e) { r1 = 0 } 
    try { r2 = arg2.toString().split(".")[1].length } catch (e) { r2 = 0 } 
    m = Math.pow(10, Math.max(r1, r2)); 
    n = (r1 >= r2) ? r1 : r2; 
    return Number(((arg1 * m - arg2 * m) / m).toFixed(n)); 
}
1
2
3
4
5
6
7
8
9

# 2.递归优化(尾递归)

// 尾递归函数 摘自阮一峰ES6 | 自己懒得写了
function tco(f) {
  let value;
  let active = false;
  let accumulated = [];

  return function accumulator() {
    accumulated.push(arguments);
    if (!active) {
      active = true;
      while (accumulated.length) {
        value = f.apply(this, accumulated.shift());
      }
      active = false;
      return value;
    }
  };
}

// 使用
新的函数 = tco(递归函数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 3.防抖 && 节流

防抖:任务频繁触发的情况下,只有任务触发的间隔超过指定间隔的时候,任务才会执行(例如搜索框,只有当用户搜索输入完成之后,停个零点几秒才会服务器发送请求,如果停顿的时间小于设定的,那就还不执行,这个就是防抖)

函数防抖就是在函数需要频繁触发情况时,只有足够空闲的时间,才执行一次。经常用于 搜索和拖拽

function debounce(fn) {
  let timeout = null; // 创建一个标记用来存放定时器的返回值
  return function () {
    clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉
    timeout = setTimeout(() => { // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数
      fn.apply(this, arguments);
    }, 500);
  };
}

debounce(fn) // 使用

1
2
3
4
5
6
7
8
9
10
11
12

节流:指定时间间隔内只会执行一次任务(例如一个一秒内连续触发的事件,如果用了节流,让其300ms触发一次,那么1s就只能触发3次)

function throttle(fn) {
  let canRun = true; // 通过闭包保存一个标记
  return function () {
    if (!canRun) return; // 在函数开头判断标记是否为true,不为true则return
    canRun = false; // 立即设置为false
    setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中
      fn.apply(this, arguments);
      // 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。当定时器没有执行的时候标记永远是false,在开头被return掉
      canRun = true;
    }, 500);
  };
}

throttle(fn) // 使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14

节流和防抖其他好的文章 (opens new window)


防抖节流其他实现

/**
 * Difference between debounce and throttle
 * In summary, 
 * throttle says, “Hey, we heard you the first time, but if you want to keep going, no problem. 
 * We’ll just ignore you for a while.” 
 * Debounce says, “Looks like you’re still busy. No problem, 
 * we’ll wait for you to finish!”
 */
/**
 * 快速书写一个防抖函数
 * @description 只要一直调用, callback 将不会被触发
 * 在一次调用结束后, 只有等待 timeout ms 时间, 才能继续调用 callback
 * immediate 决定触发时机
 * @example 
 * 1. 点击按钮发送请求(保存数据之类的)
 * 2. 搜索时自动联想
 * 3. 自动保存
 * 4. Debouncing a resize/scroll event handler
 */
function debounce(callback, timeout, immediate) {
  let timer;
  return function () {
    const context = this; // 持有执行上下文
    const args = arguments; // 记录传参
    const later = function () {
      timer = null; // 贤者时间过了,重振旗鼓,重置为初始状态
      if (!immediate) callback.apply(context, args); // 设置为尾部调用才延时触发
    }
    const callNow = immediate && !timer; // 如果确认允许首部调用,且首次调用,那么本次立即触发
    clearTimeout(timer); // 杀掉上次的计时器,重新计时
    timer = setTimeout(later, timeout); // 重启一个计时器,过了贤者时间之后才触发
    callNow && callback.apply(context, args); // 设置为首部调用立即触发
  }
}

/**
 *  快速书写一个节流函数
 * @description 一直调用 callback, 每隔 timeout ms 时间 callback 触发一次
 * 在 timeout ms 时间内的调用将不触发
 * @example
 * 1. Throttling a button click so we can’t spam click 控制疯狂按钮的响应频率
 * 2. Throttling an API call 控制 API 的调用频率
 * 3. Throttling a mousemove/touchmove event handler 控制频繁触发事件的相应频率
 */
// solution1 记录时间比较
function throttle(callback, timeout) {
  let triggerTime; // 记录每次真正触发时间
  return function () {
    const context = this; // 持有执行上下文
    const args = arguments; // 记录传参
    if (triggerTime === undefined // 首次调用
      || Date.now() - triggerTime > timeout) { // 贤者时间已经过去
      triggerTime = Date.now(); // 记录真正触发时间
      callback.apply(context, args); // 可以触发回调
    }
  }
}
// solution2 间隔时间反转标志位
function throttle(callback, timeout) {
  let disable; // 触发回调是否禁用
  return function () {
    const context = this; // 持有执行上下文
    const args = arguments; // 记录传参
    if (!disable) { // 首次调用或者贤者时间过了,禁用解除
      callback.apply(context, args); // 可以触发回调
      disable = true; // 马上禁用
      setTimeout(_ => disable = false, timeout); // 贤者时间过了,禁用解除
    }
  }
}
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
62
63
64
65
66
67
68
69
70

# 🍹第七部分:其他

# 1.Math函数的一些应用

parseInt(5.12) // 5 | 只保留整数部分(丢弃小数部分)
Math.floor(5.12) // 5 | 向下取整(效果和parseInt一样)
Math.ceil(5.12) // 6 | 向上取整(有小数,整数就+1)

Math.round(5.499) // 5 | 四舍五入
Math.round(5.501) // 6 | 四舍五入

Math.abs(-5) // 5 | 绝对值

Math.max(5, 6) // 6 | 返回两者中较大的数
Math.min(5, 6) // 5 | 返回两者中较小的数

Math.random() // 随机数 (0-1)
1
2
3
4
5
6
7
8
9
10
11
12
13

# 2.常用正则速查

消除字符串首尾两端的空格(替换)

let reg = /^\s+|\s+$/g;

let str = ' #id div.class '; 
str.replace(reg, '') // "#id div.class"
1
2
3
4

*把手机号码替换成 (替换)

var reg = /1[24578]\d{9}/;

var str = '姓名:柠栀 手机:15932638907'; // 手记号瞎写的
str.replace(reg, '***') //"姓名:柠栀 手机:***"
1
2
3
4

替换敏感字(替换)

let str = '中国共产党中国人民解放军中华人民共和国';
    
let r = str.replace(/中国|军/g, input => {
    let t = '';
    for (let i = 0; i<input.length; i++) {
        t += '*';
    }
    return t;
})
     
console.log(r); //**共产党**人民解放*中华人民共和国   
1
2
3
4
5
6
7
8
9
10
11

千位分隔符(替换)

let reg = /(\d)(?=(?:\d{3})+$)/g

let str = '100002003232322';    
let r = str.replace(, '$1,'); //100,002,003,232,322
1
2
3
4

匹配网页标签(匹配)

var reg = /<(.+)>.+<\/\1>/;

var str = '柠栀<div>2707509@.qq.com</div>柠栀';    
str.match(reg); // ["<div>2707509@.qq.com</div>"]
1
2
3
4

验证手记号(验证)

let reg = /^1((3[\d])|(4[5,6,9])|(5[0-3,5-9])|(6[5-7])|(7[0-8])|(8[1-3,5-8])|(9[1,8,9]))\d{8}$/;

reg.test('15932539095'); //true
reg.test('234554568997'); //false
1
2
3
4

验证邮箱地址(验证)

let reg = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/

reg.test('2775033@hotmail.com'); //true
reg.test('abc@'); //false
1
2
3
4

验证身份证(验证)

let reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/

reg.test('31210119651230518X'); //true 自己瞎写的
reg.test('2101196523s230518X'); //false 自己瞎写的
1
2
3
4

验证中国邮箱编码(验证)

let reg = /^(0[1-7]|1[0-356]|2[0-7]|3[0-6]|4[0-7]|5[1-7]|6[1-7]|7[0-5]|8[013-6])\d{4}$/

reg.test('065900'); //true
reg.test('999999'); //false
1
2
3
4

验证ipv4地址正则(验证)

let reg = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/

reg.test('192.168.1.192'); //true
reg.test('127.0.0.1s'); //false
1
2
3
4

验证银行卡号(16或19位)

let reg = /^([1-9]{1})(\d{15}|\d{18})$/

reg.test('6222026006705354218') // true
1
2
3

验证中文姓名(验证)

let reg = /^([\u4e00-\u9fa5\·]{2,10})$/

reg.test('柠栀'); //true
reg.test('Zhu Kunpeng'); //false
1
2
3
4

# 3.变换变量


// [letA,letB] = [letB,letA];

let a = 1;
let b = 2;
[a, b] = [b, a] // a = 2 b = 1

1
2
3
4
5
6
7

# 4.格式化对象为JSON代码

const formatted = JSON.stringify({name: 'Jhon', age: 18, address: 'sz'}, null, 4);
/*
{
    "name": "Jhon",
    "age": 18,
    "address": "sz"
}
*/

// 该字符串化命令有三个参数。第一个是Javascript对象。第二个是可选函数,可用于在JSON进行字符串化时对其执行操作。最后一个参数指示要添加多少空格作为缩进以格式化JSON。省略最后一个参数,JSON将返回一个长行。如果myObj中存在循环引用,则会格式失败。
1
2
3
4
5
6
7
8
9
10

# 5.随机生成六位数字验证码

const code = Math.floor(Math.random() * 1000000).toString().padStart(6, "0") // 942377
1

# 6.RGB 颜色转 16进制颜色

const RGBToHex = (r, g, b) => ((r << 16) + (g << 8) + b).toString(16).padStart(6, '0');
RGBToHex(255, 165, 1); // 'ffa501'
1
2

# 7.生成随机整数

function randomNum(min, max) {
  switch (arguments.length) {
    case 1:
      return parseInt(Math.random() * min + 1, 10)
    case 2:
      return parseInt(Math.random() * (max - min + 1) + min, 10)
    default:
      return 0
  }
}

randomNum(1,10) // 随机 [1,10]的整数
1
2
3
4
5
6
7
8
9
10
11
12

# 8.去除空格(1-所有空格 2-前后空格 3-前空格 4-后空格 默认为1)


/**
 * trim 去除空格
 * param1  string str 待处理字符串
 * param2  number type 去除空格类型 1-所有空格  2-前后空格  3-前空格 4-后空格 默认为1
 * return  string str 处理后的字符串
 */
function trim(str, type = 1) {
    if (type && type !== 1 && type !== 2 && type !== 3 && type !== 4) return;
    switch (type) {
        case 1:
            return str.replace(/\s/g, "");
        case 2:
            return str.replace(/(^\s)|(\s*$)/g, "");
        case 3:
            return str.replace(/(^\s)/g, "");
        case 4:
            return str.replace(/(\s$)/g, "");
        default:
            return str;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 9.大小写转换


/**
 * 大小写转换
 * param1 string str 待转换的字符串
 * param2 number type 1-全大写 2-全小写 3-首字母大写 
 * return  string str 处理后的字符串
 */

function turnCase(str, type) {
    switch (type) {
        case 1:
            return str.toUpperCase()
        case 2:
            return str.toLowerCase();
        case 3:
            return str[0].toUpperCase() + str.substr(1).toLowerCase()
        default:
            return str;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 10.随机16进制颜色 hexColor

/**
 * 随机16进制颜色 hexColor
 * return  string str 带#号的随机16进制颜色
 */

function hexColor() {

    let str = '#';
    let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'A', 'B', 'C', 'D', 'E', 'F'];
    for (let i = 0; i < 6; i++) {
        let index = Number.parseInt(Math.random() * 16);
        str += arr[index]
    }
    return str;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 11.统计一段文字中指定文字出现次数 keywordsCount(骚操作)

/**
 * 关键词统计:统计一段文字中指定文字出现次数 keywordsCount
 * param1 string text 进行统计的文本
 * param2 string keywords 进行统计的关键词
 * return number count 关键词出现次数
 * tip:param1 document.body.innerText--全文统计
 */

function keywordsCount(text, keywords) {
    return text.split(keywords).length - 1
}

1
2
3
4
5
6
7
8
9
10
11
12

# 12.好的笔记文章


# 13. 轮询等待函数

/**
 * 轮询等待函数
 * 
 * @param {Function} 轮询结束的条件
 * @param {Function} 成功之后的回调函数
 * @param {Number} 轮询时间(默认100ms)
 * @param {Number} 轮询最长的时间(默认1000ms)
 */
function pollingWaiting (callBack, resCallBack, time = 100, lastTime = 1000) {
  
  let startTime = Date.now()
  let t = null;
  let fn =  function () {
      t = setTimeout(() => {
          if (!callBack()) {
              // 此处可以采用尾递归优化,来防止占用过多内存
              console.log('startTime', Date.now() - startTime > lastTime)
              (Date.now() - startTime > lastTime) ? window.clearInterval(t) : fn()
          } else {
              resCallBack()
          }
      }, time);
  }
  fn()
}

// 示例
let a = 1;
setTimeout( () => {
  a = 2
}, 500)

pollingWaiting( () => {
  return a === 2
}, () => {
  console.log('触发了', a)
}, 100, 800)

// 4 startTime false
// 触发了 2
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

# 14.大数值转换为万,亿

/**
 * 大数值转换为万,亿函数
 * 
 * @param {Number} 大数
 * @param {Number} 保留几位小数
 */
function numConversion (num, point = 2) {

  let numStr = num.toString().split('.')[0] // 去掉小数点后的数值字符串
  let numLen = numStr.length

  if (numLen < 6) {
    return numStr
  } else if (numLen >= 6 && numLen <= 8) {
    let decimal = numStr.substring(numLen - 4, numLen - 4 + point)
    let res = parseInt(num / 10000) + '.' + decimal + '万'
    return res
  } else if (numLen > 8) {
    let decimal = numStr.substring(numLen - 8, numLen - 8 + point)
    let res = parseInt(num / 100000000) + '.' + decimal + '亿'
    return res
  }
}

numConversion(12345) // 12345
numConversion(1234567) // 123.45万
numConversion(123456789) // 1.23亿
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

# 15.常见的XSS转义场景

// 转义HTML特殊字符
function HtmlEncode(str) {
    var hex = new Array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f');
    var preescape = str;
    var escaped = "";
    for(var i = 0; i < preescape.length; i++){
        var p = preescape.charAt(i);
        escaped = escaped + escapeCharx(p);
    }
    
    return escaped;
                    
    function escapeCharx(original){
        var found=true;
        var thechar=original.charCodeAt(0);
        switch(thechar) {
            case 10: return "<br/>"; break; //newline
            case 32: return "&nbsp;"; break; //space
            case 34:return "&quot;"; break; //"
            case 38:return "&amp;"; break; //&
            case 39:return "&#x27;"; break; //'
            case 47:return "&#x2F;"; break; // /
            case 60:return "&lt;"; break; //<
            case 62:return "&gt;"; break; //>
            case 198:return "&AElig;"; break;
            case 193:return "&Aacute;"; break;
            case 194:return "&Acirc;"; break; 
            case 192:return "&Agrave;"; break; 
            case 197:return "&Aring;"; break; 
            case 195:return "&Atilde;"; break; 
            case 196:return "&Auml;"; break; 
            case 199:return "&Ccedil;"; break; 
            case 208:return "&ETH;"; break;
            case 201:return "&Eacute;"; break; 
            case 202:return "&Ecirc;"; break; 
            case 200:return "&Egrave;"; break; 
            case 203:return "&Euml;"; break;
            case 205:return "&Iacute;"; break;
            case 206:return "&Icirc;"; break; 
            case 204:return "&Igrave;"; break; 
            case 207:return "&Iuml;"; break;
            case 209:return "&Ntilde;"; break; 
            case 211:return "&Oacute;"; break;
            case 212:return "&Ocirc;"; break; 
            case 210:return "&Ograve;"; break; 
            case 216:return "&Oslash;"; break; 
            case 213:return "&Otilde;"; break; 
            case 214:return "&Ouml;"; break;
            case 222:return "&THORN;"; break; 
            case 218:return "&Uacute;"; break; 
            case 219:return "&Ucirc;"; break; 
            case 217:return "&Ugrave;"; break; 
            case 220:return "&Uuml;"; break; 
            case 221:return "&Yacute;"; break;
            case 225:return "&aacute;"; break; 
            case 226:return "&acirc;"; break; 
            case 230:return "&aelig;"; break; 
            case 224:return "&agrave;"; break; 
            case 229:return "&aring;"; break; 
            case 227:return "&atilde;"; break; 
            case 228:return "&auml;"; break; 
            case 231:return "&ccedil;"; break; 
            case 233:return "&eacute;"; break;
            case 234:return "&ecirc;"; break; 
            case 232:return "&egrave;"; break; 
            case 240:return "&eth;"; break; 
            case 235:return "&euml;"; break; 
            case 237:return "&iacute;"; break; 
            case 238:return "&icirc;"; break; 
            case 236:return "&igrave;"; break; 
            case 239:return "&iuml;"; break; 
            case 241:return "&ntilde;"; break; 
            case 243:return "&oacute;"; break;
            case 244:return "&ocirc;"; break; 
            case 242:return "&ograve;"; break; 
            case 248:return "&oslash;"; break; 
            case 245:return "&otilde;"; break;
            case 246:return "&ouml;"; break; 
            case 223:return "&szlig;"; break; 
            case 254:return "&thorn;"; break; 
            case 250:return "&uacute;"; break; 
            case 251:return "&ucirc;"; break; 
            case 249:return "&ugrave;"; break; 
            case 252:return "&uuml;"; break; 
            case 253:return "&yacute;"; break; 
            case 255:return "&yuml;"; break;
            case 162:return "&cent;"; break; 
            case '\r': break;
            default:
                found=false;
                break;
        }
        if(!found){
            if(thechar>127) {
                var c=thechar;
                var a4=c%16;
                c=Math.floor(c/16); 
                var a3=c%16;
                c=Math.floor(c/16);
                var a2=c%16;
                c=Math.floor(c/16);
                var a1=c%16;
                return "&#x"+hex[a1]+hex[a2]+hex[a3]+hex[a4]+";";        
            }
            else{
                return original;
            }
        }    
    }
}

// 转义JS特殊字符
function JavaScriptEncode(str) 
     
    var hex=new Array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f');
        
    function changeTo16Hex(charCode){
        return "\\x" + charCode.charCodeAt(0).toString(16);
    }
    
    function encodeCharx(original) {
        
        var found = true;
        var thecharchar = original.charAt(0);
        var thechar = original.charCodeAt(0);
        switch(thecharchar) {
            case '\n': return "\\n"; break; //newline
            case '\r': return "\\r"; break; //Carriage return
            case '\'': return "\\'"; break;
            case '"': return "\\\""; break;
            case '\&': return "\\&"; break;
            case '\\': return "\\\\"; break;
            case '\t': return "\\t"; break;
            case '\b': return "\\b"; break;
            case '\f': return "\\f"; break;
            case '/': return "\\x2F"; break;
            case '<': return "\\x3C"; break;
            case '>': return "\\x3E"; break;
            default:
                found=false;
                break;
        }
        if(!found){
            if(thechar > 47 && thechar < 58){ //数字
                return original;
            }
            
            if(thechar > 64 && thechar < 91){ //大写字母
                return original;
            }

            if(thechar > 96 && thechar < 123){ //小写字母
                return original;
            }        
            
            if(thechar>127) { //大于127用unicode
                var c = thechar;
                var a4 = c%16;
                c = Math.floor(c/16); 
                var a3 = c%16;
                c = Math.floor(c/16);
                var a2 = c%16;
                c = Math.floor(c/16);
                var a1 = c%16;
                return "\\u"+hex[a1]+hex[a2]+hex[a3]+hex[a4]+"";        
            }
            else {
                return changeTo16Hex(original);
            }
            
        }
    }     
  
    var preescape = str;
    var escaped = "";
    var i=0;
    for(i=0; i < preescape.length; i++){
        escaped = escaped + encodeCharx(preescape.charAt(i));
    }
    return escaped;
}
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
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181

# 📚参考列表(致敬)