JS自省系列-1

去除字符串中最后一个指定的字符

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 去除字符串中最后一个指定的字符
* @param {String} str
* @param {String} del
*/
function delLast(str, del) {
if (typeof str !== "string") throw new Error("必须为字符串");
//查找字符串的位置
let index = str.lastIndexOf(del);
//index之前的字符串+index之后的字符串
if(index > -1) return str.substring(0, index) + str.substring(index + 1, str.length);
return str;
}

把下划线字符串转化为驼峰

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 将下划线字符串转化为驼峰命名
* @param {String} str
*/
function toCamelName(str) {
if (typeof str !== "string") return str;
//分割为数组
let strArr = str.split("_");
let upperCaseArr = strArr.map((item, i) => {
if (i > 0) {
return item.charAt(0).toUpperCase() + item.substr(1, item.length);
}
return item;
});
return upperCaseArr.join("");
}
console.log(toCamelName("dd_dd")); //ddDd

把一个字符串大小写切换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 将大写转小写 小写转大写
* @param {String} str
*/
function toReverse(str) {
if (typeof str !== "string") return str;
return str
.split("")
.map((item) =>
/[A-Z]/.test(item) ? item.toLowerCase() : item.toUpperCase()
)
.join("");
}
console.log(toReverse("aBcD")); //AbCd

去除制表符

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

/**
* \n 换行符 new line
* \r 回车符 return
* \t 制表符 tab
* \b 退格符 backspace
* \f 换页符 form feed
* @param {String} str
*/
function fn(str) {
return str.replace(/[\t\n]/g, "");
}

统计某一字符在另一个字符中出现的次数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 统计needFind字符在target出现几次
* @param {String} target
* @param {String} needFind
*/
function strFindCount(target, needFind) {
//通过字符分隔数组
return target.split(needFind).length - 1;
}

function strFindCount2(target, needFind) {
const reg = new RegExp(needFind, "g");
return target.match(reg).length;
}

判断数据类型

1
2
3
4
5
6
7
8
9
10
/**
* 判断数据类型
* @param {*} param
*/
function typeCheck(param) {
//[object Array]
const typeStr = Object.prototype.toString.call(param);
//截取掉object
return typeStr.toLowerCase().slice(8, typeStr.length - 1);
}

JS内置对象

  • String,RegExp
  • Array
  • Number,BigInt,Math,Date
  • Objcet
  • Function
  • Error
  • JSON
  • Map,Set,WeakMap,WeakSet

获取连接中的查询参数

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 获取链接中的查询参数
* @param {String} url
*/
function getQuery(url) {
const query = url.substr(url.indexOf("?") + 1);
let result = {};
query.split("&").forEach((item) => {
[key, value] = item.split("=");
result[key] = value;
});
return result;
}

作用域的理解

正常情况下JS中的作用域是在编写代码时候决定的,编译器在编译的时候,通过词法分析知道标识符在哪里和如何声明,相当于已经有映射关系一样.

作用域就像是一个个气泡一样,标识符从属于哪个标识符,那么就只能在那个气泡范围内访问

  • 全局作用域: 顶级作用域,任何地方都能访问到
  • 函数作用域: 只能在函数内访问,闭包可以访问包围他的函数
  • 块作用域: ES6新增的,只能在块内访问

什么是闭包

  • 闭包可以访问另一个函数作用域的函数

  • 闭包就是一个函数可以在脱离了声明函数的环境时还可以运行,并且可以调用当时环境内的变量

  • 闭包以及当时声明环境的变量,保存在内存中,所以闭包是占用内存的

  • 闭包可以防止变量污染作用域,作为函数内的私有变量

  • 不主动释放的情况下,无法回收

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    function incrementNum() {
    let num = 0;
    return function () {
    return (num += 1);
    };
    }

    // 此处函数执行完毕后 没有其他引用 会被释放回收
    console.log(incrementNum()()); //1
    console.log(incrementNum()()); //1

    // 此处被fn引用,闭包以及变量一直保存在内存中,没有得到释放
    var fn = incrementNum();
    console.log(fn());
    console.log(fn());
    console.log(fn());
    // 手动释放
    fn = null;

数组去重

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
const arr = [1, 3, 4, 2, 1, [1, 2, [5, 6]]];
function uniqueArr(arr) {
//数据扁平化,逗号相连的字符串,再转为数组
const flatArr = arr.join(",").split(",");
return Array.from(new Set(flatArr));
}
console.log(uniqueArr(arr)); //[ '1', '3', '4', '2', '5', '6' ]
/**
* 递归去重
* @param {Array} arr
* @param {Array} result
*/
function reduceUniqueArr(arr,result = []) {
arr.forEach(item => {
if(Array.isArray(item)) {
reduceUniqueArr(item,result);
}else {
if(!result.includes(item)) {
result.push(item);
}
}
})
return result;
}
console.log(reduceUniqueArr(arr)); ////[ '1', '3', '4', '2', '5', '6' ]

返回顶部

1
2
3
4
5
6
//更改scrollTop
document.documentElement.scrollTop = 0;
//url加#
location.href += "#";
//a标签加锚点
<a href="#top" target="_self">回到顶部</a>

验证是否为中文

1
2
3
4
5
6
7
8
/**
* 验证是否为中文
* u4e00-u9fa5 表示第一个汉子和最后一个汉子的编码
* @param {String} str
*/
function isChinese(str) {
return /^[\u4e00-\u9fa5]+$/.test(str);
}

快速打乱数组顺序

洗牌算法

  1. 倒序循环这个数组
  2. 取范围从1到n的随机数k
  3. k与n交换
  4. 直到循环至数组的首个元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Array.prototype.shuffle = function () {
const input = this;
const arrLength = input.length - 1;
//倒序循环数组
for (let i = arrLength; i >= 0; i--) {
//从 [1-数组长度]中随即取一个值
let randomIndex = Math.floor(Math.random() * (i + 1));
//当前index对应的值
let itemAtIndex = input[randomIndex];
//当前index的值和范围最大值i互换
input[randomIndex] = input[i];
input[i] = itemAtIndex;
}
return input;
};
let tempArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
tempArray.shuffle();
console.log(tempArray);

为什么10.toFixed(10)会报错

因为 JS 的解释器对 . 操作符产生了歧义。在 JS 中 . 可以表示小数和从对象中取值。在这个例子中, 由于 10 是整数,所以在 10. 默认是小数点,因此会报错

解决的办法有下面几种:

  • (10).toFixed(10)
  • 10..toFixed(10)

内存泄露有哪些

  • 死循环
  • 过度递归
  • 对页面中的一些 副作用没有清除
  • 闭包