自省系列JS-1

207 阅读4分钟

前端自省系列,有些是掘友的一些专栏文章的摘录

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

/**
 * 去除字符串中最后一个指定的字符
 * @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;
}

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

/**
 * 将下划线字符串转化为驼峰命名
 * @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 

把一个字符串大小写切换

/**
 * 将大写转小写 小写转大写
 * @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

去除制表符


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

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

/**
 * 统计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;
}

判断数据类型

/**
 * 判断数据类型
 * @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

获取连接中的查询参数

/**
 * 获取链接中的查询参数
 * @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新增的,只能在块内访问

什么是闭包

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

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

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

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

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

    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;
    

数组去重

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' ]

返回顶部

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

验证是否为中文

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

快速打乱数组顺序

洗牌算法

  1. 倒序循环这个数组
  2. 取范围从1到n的随机数k
  3. k与n交换
  4. 直到循环至数组的首个元素
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)

内存泄露有哪些

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