前端手写(正则、字符串、函数)

2023-11-19

1 实现千位分隔符

// 保留三位小数
parseToMoney(1234.56); // return '1,234.56'
parseToMoney(123456789); // return '123,456,789'
parseToMoney(1087654.321); // return '1,087,654.321'
 function parseToMoney(num) {
            // toFixed(3) 函数将 num 保留三位小数并返回一个字符串
            num = parseFloat(num.toFixed(3));
            // 整个表达式的作用就是将整数的末尾到倒数第三位的每个三个数字字符的连续出现(即千位)前插入逗号
            let [integer, decimal] = String.prototype.split.call(num, '.');
            integer = integer.replace(/\d(?=(\d{3})+$)/g, '$&,');
            return integer + '.' + (decimal ? decimal : '');
        }

2 判断是否是电话号码

function isPhone(tel) {
            var regx = /^1[34578]\d{9}$/;
            return regx.test(tel);
        }

3 验证是否是邮箱

 function isEmail(email) {
            var regx = /^([a-zA-Z0-9_\-])+@([a-zA-Z0-9_\-])+(\.[a-zA-Z0-9_\-])+$/;
            return regx.test(email);
        }

4 验证是否是身份证

  function isCardNo(number) {
            var regx = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
            return regx.test(number);
        }

5 用正则写一个根据name获取cookie中的值的方法

function getCookie(name) {
            var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]*)'));
            if (match) return decodeURIComponent(match[2])
        }

函数柯里化相关

1 实现一个JS函数柯里化

预先处理的思想,利用闭包的机制

柯里化的定义:接收一部分参数,返回一个函数接收剩余参数,接收足够参数后,执行原函数

函数柯里化的主要作用和特点就是参数复用提前返回延迟执行

 function curry(fn, args) {
            var length = fn.length;
            var args = args || [];
            return function () {
                newArgs = args.concat(Array.prototype.slice.call(arguments));
                if (newArgs.length < length) {
                    return curry.call(this, fn, newArgs);
                } else {
                    return fn.apply(this, newArgs);
                }
            }
        }
        const curry = (fn, arr = []) => { // arr就是我们要收集每次调用时传入的参数
            let len = fn.length; // 函数的长度,就是参数的个数
            return function (...args) {
                let newArgs = [...arr, ...args] // 收集每次传入的参数
                // 如果传入的参数个数等于我们指定的函数参数个数,就执行指定的真正函数
                if (newArgs.length === len) {
                    return fn(...newArgs)
                } else {
                    // 递归收集参数
                    return curry(fn, newArgs)
                }
            }
        }
        // 测试
        function multiFn(a, b, c) {
            return a * b * c;
        }

        var multi = curry(multiFn);

        multi(2)(3)(4);
        multi(2, 3, 4);
        multi(2)(3, 4);
        multi(2, 3)(4)

ES6写法

const curry = (fn, arr = []) => (...args) => (
            arg => arg.length === fn.length ?
            fn(...arg) :
            curry(fn, arg)
        )([...arr, ...args])
// 柯里化简单应用
// 判断类型,参数多少个,就执行多少次收集
function isType(type, val) {
  return Object.prototype.toString.call(val) === `[object ${type}]`
}

let newType = curry(isType)

// 相当于把函数参数一个个传了,把第一次先缓存起来
let isString = newType('String')
let isNumber = newType('Number')

isString('hello world')
isNumber(999)

2 请实现一个 add 函数,满足以下功能

add(1); 			// 1
add(1)(2);  	// 3
add(1)(2)(3);// 6
add(1)(2, 3); // 6
add(1, 2)(3); // 6
add(1, 2, 3); // 6
 function add(...args) {
            // 在内部声明一个函数,利用闭包的特性保存并收集所有的参数值
            let fn = function (...newArgs) {
                return add.apply(null, args.concat(newArgs))
            }
            // 利用toString隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
            fn.toString = function () {
                return args.reduce((total, curr) => total + curr)
            }
            return fn
        }

        // 测试,调用toString方法触发求值

add(1).toString(); 			// 1
add(1)(2).toString();  	// 3
add(1)(2)(3).toString();// 6
add(1)(2, 3).toString(); // 6
add(1, 2)(3).toString(); // 6
add(1, 2, 3).toString(); // 6

 

 

3 实现 (5).add(3).minus(2) 功能

例: 5 + 3 - 2,结果为 6

   Number.prototype.add = function (n) {
            return this.valueOf() + n;
        };
        Number.prototype.minus = function (n) {
            return this.valueOf() - n;
        };

实现add(1)(2) =3

  // 题意的答案
        const add = (num1) => (num2) => num2 + num1;

        // 整了一个加强版 可以无限链式调用 add(1)(2)(3)(4)(5)....
        function add(x) {
            // 存储和
            let sum = x;

            // 函数调用会相加,然后每次都会返回这个函数本身
            let tmp = function (y) {
                sum = sum + y;
                return tmp;
            };

            // 对象的toString必须是一个方法 在方法中返回了这个和
            tmp.toString = () => sum
            return tmp;
        }

        alert(add(1)(2)(3)(4)(5))

32 字符串相关

1 查找字符串中出现最多的字符和个数

在此函数中,第一个参数 $0 表示完整的匹配子字符串,而第二个参数 $1 表示匹配中第一个捕获组的内容。

let str = "abcabcabcbbccccc";
        let num = 0;
        let char = '';
        // 使其按照一定的次序排列
        str = str.split('').sort().join('');
        // "aaabbbbbcccccccc"
        // 定义正则表达式
        let re = /(\w)\1+/g;
        str.replace(re, ($0, $1) => {
            if (num < $0.length) {
                num = $0.length;
                char = $1;
            }
        });
        console.log(`字符最多的是${char},出现了${num}次`);

2 字符串查找

请使用最基本的遍历来实现判断字符串 a 是否被包含在字符串 b 中,并返回第一次出现的位置(找不到返回 -1)。

a='34';b='1234567'; // 返回 2
a='35';b='1234567'; // 返回 -1
a='355';b='12354355'; // 返回 5
isContain(a,b);
function isContain(a, b) {
            for (let i in b) {
                if (a[0] === b[i]) {
                    let tmp = true;
                    for (let j in a) {
                        if (a[j] !== b[~~i + ~~j]) {
                            tmp = false;
                        }
                    }
                    if (tmp) {
                        return i;
                    }
                }
            }
            return -1;
        }

3 字符串最长的不重复子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。


示例 1:

输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

示例 4:

输入: s = ""
输出: 0
 const lengthOfLongestSubstring = function (s) {
            if (s.length === 0) {
                return 0;
            }

            let left = 0;
            let right = 1;
            let max = 0;
            while (right <= s.length) {
                let lr = s.slice(left, right);
                const index = lr.indexOf(s[right]);
                if (index > -1) {
                    left = index + left + 1;
                } else {
                    lr = s.slice(left, right + 1);
                    max = Math.max(max, lr.length);
                }
                right++;
            }
            return max;
        };

33 实现工具函数

1 对象扁平化

 function objectFlat(obj = {}) {
            const res = {}

            function flat(item, preKey = '') {
                Object.entries(item).forEach(([key, val]) => {
                    const newKey = preKey ? `${preKey}.${key}` : key
                    if (val && typeof val === 'object') {
                        flat(val, newKey)
                    } else {
                        res[newKey] = val
                    }
                })
            }
            flat(obj)
            return res
        }

        // 测试
        const source = {
            a: {
                b: {
                    c: 1,
                    d: 2
                },
                e: 3
            },
            f: {
                g: 2
            }
        }
        console.log(objectFlat(source));

2 实现一个管理本地缓存过期的函数

封装一个可以设置过期时间的localStorage存储函数

let storage = new Storage();
storage.setItem({
  name:"name",
  value:"ppp"
})
class Storage {
            constructor(name) {
                this.name = 'storage';
            }
            //设置缓存
            setItem(params) {
                let obj = {
                    name: '', // 存入数据  属性
                    value: '', // 属性值
                    expires: "", // 过期时间
                    startTime: new Date().getTime() //记录何时将值存入缓存,毫秒级
                }
                let options = {};
                //将obj和传进来的params合并
                Object.assign(options, obj, params);
                if (options.expires) {
                    //如果options.expires设置了的话
                    //以options.name为key,options为值放进去
                    localStorage.setItem(options.name, JSON.stringify(options));
                } else {
                    //如果options.expires没有设置,就判断一下value的类型
                    let type = Object.prototype.toString.call(options.value);
                    //如果value是对象或者数组对象的类型,就先用JSON.stringify转一下,再存进去
                    if (Object.prototype.toString.call(options.value) == '[object Object]') {
                        options.value = JSON.stringify(options.value);
                    }
                    if (Object.prototype.toString.call(options.value) == '[object Array]') {
                        options.value = JSON.stringify(options.value);
                    }
                    localStorage.setItem(options.name, options.value);
                }
            }
            //拿到缓存
            getItem(name) {
                let item = localStorage.getItem(name);
                //先将拿到的试着进行json转为对象的形式
                try {
                    item = JSON.parse(item);
                } catch (error) {
                    //如果不行就不是json的字符串,就直接返回
                    item = item;
                }
                //如果有startTime的值,说明设置了失效时间
                if (item.startTime) {
                    let date = new Date().getTime();
                    //何时将值取出减去刚存入的时间,与item.expires比较,如果大于就是过期了,如果小于或等于就还没过期
                    if (date - item.startTime > item.expires) {
                        //缓存过期,清除缓存,返回false
                        localStorage.removeItem(name);
                        return false;
                    } else {
                        //缓存未过期,返回值
                        return item.value;
                    }
                } else {
                    //如果没有设置失效时间,直接返回值
                    return item;
                }
            }
            //移出缓存
            removeItem(name) {
                localStorage.removeItem(name);
            }
            //移出全部缓存
            clear() {
                localStorage.clear();
            }
        }

设置5秒过期

let storage = new Storage();
storage.setItem({
  name:"name",
  value:"ppp",
  expires: 5000
})
// 过期后再取出来会变为 false
let value = storage.getItem('name');
console.log('我是value',value);

3 实现lodash的chunk方法--数组按指定长度拆分

/**
 * @param input
 * @param size
 * @returns {Array}
 */
_.chunk(['a', 'b', 'c', 'd'], 2)
// => [['a', 'b'], ['c', 'd']]

_.chunk(['a', 'b', 'c', 'd'], 3)
// => [['a', 'b', 'c'], ['d']]

_.chunk(['a', 'b', 'c', 'd'], 5)
// => [['a', 'b', 'c', 'd']]

_.chunk(['a', 'b', 'c', 'd'], 0)
// => []

 

 
function chunk(arr, length) {
  let newArr = [];
  for (let i = 0; i < arr.length; i += length) {
    newArr.push(arr.slice(i, i + length));
  }
  return newArr;
}

4 手写深度比较isEqual

思路:深度比较两个对象,就是要深度比较对象的每一个元素。=> 递归

  • 递归退出条件:
    • 被比较的是两个值类型变量,直接用“===”判断
    • 被比较的两个变量之一为null,直接判断另一个元素是否也为null
  • 提前结束递推:
    • 两个变量keys数量不同
    • 传入的两个参数是同一个变量
  • 递推工作:  - 深度比较每一个key
 function isEqual(obj1, obj2) {
            //其中一个为值类型或null
            if (!isObject(obj1) || !isObject(obj2)) {
                return obj1 === obj2;
            }

            //判断是否两个参数是同一个变量
            if (obj1 === obj2) {
                return true;
            }

            //判断keys数是否相等
            const obj1Keys = Object.keys(obj1);
            const obj2Keys = Object.keys(obj2);
            if (obj1Keys.length !== obj2Keys.length) {
                return false;
            }

            //深度比较每一个key
            for (let key in obj1) {
                if (!isEqual(obj1[key], obj2[key])) {
                    return false;
                }
            }

            return true;
        }

5 实现一个JSON.stringify

JSON.stringify(value[, replacer [, space]]):
  • Boolean | Number| String类型会自动转换成对应的原始值。
  • undefined、任意函数以及symbol,会被忽略(出现在非数组对象的属性值中时),或者被转换成 null(出现在数组中时)。
  • 不可枚举的属性会被忽略如果一个对象的属性值通过某种间接的方式指回该对象本身,即循环引用,属性也会被忽略
  • 如果一个对象的属性值通过某种间接的方式指回该对象本身,即循环引用,属性也会被忽略
 function jsonStringify(obj) {
            let type = typeof obj;
            if (type !== "object") {
                if (/string|undefined|function/.test(type)) {
                    obj = '"' + obj + '"';
                }
                return String(obj);
            } else {
                let json = []
                let arr = Array.isArray(obj)
                for (let k in obj) {
                    let v = obj[k];
                    let type = typeof v;
                    if (/string|undefined|function/.test(type)) {
                        v = '"' + v + '"';
                    } else if (type === "object") {
                        v = jsonStringify(v);
                    }
                    json.push((arr ? "" : '"' + k + '":') + String(v));
                }
                return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}")
            }
        }
        jsonStringify({
            x: 5
        }) // "{"x":5}"
        jsonStringify([1, "false", false]) // "[1,"false",false]"
        jsonStringify({
            b: undefined
        }) // "{"b":"undefined"}"

6 实现一个JSON.parse

用来解析JSON字符串,构造由字符串描述的JavaScript值或对象。提供可选的reviver函数用以在返回之前对所得到的对象执行变换(操作)

function jsonParse(opt) {
    return eval('(' + opt + ')');
}
jsonParse(jsonStringify({x : 5}))
// Object { x: 5}
jsonParse(jsonStringify([1, "false", false]))
// [1, "false", falsr]
jsonParse(jsonStringify({b: undefined}))
// Object { b: "undefined"}

7 解析 URL Params 为对象

let url = 'http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled';
parseParam(url)
/* 结果
{ user: 'anonymous',
  id: [ 123, 456 ], // 重复出现的 key 要组装成数组,能被转成数字的就转成数字类型
  city: '北京', // 中文需解码
  enabled: true, // 未指定值得 key 约定为 true
}
*/
function parseParam(url) {
  const paramsStr = /.+\?(.+)$/.exec(url)[1]; // 将 ? 后面的字符串取出来
  const paramsArr = paramsStr.split('&'); // 将字符串以 & 分割后存到数组中
  let paramsObj = {};
  // 将 params 存到对象中
  paramsArr.forEach(param => {
    if (/=/.test(param)) { // 处理有 value 的参数
      let [key, val] = param.split('='); // 分割 key 和 value
      val = decodeURIComponent(val); // 解码
      val = /^\d+$/.test(val) ? parseFloat(val) : val; // 判断是否转为数字

      if (paramsObj.hasOwnProperty(key)) { // 如果对象有 key,则添加一个值
        paramsObj[key] = [].concat(paramsObj[key], val);
      } else { // 如果对象没有这个 key,创建 key 并设置值
        paramsObj[key] = val;
      }
    } else { // 处理没有 value 的参数
      paramsObj[param] = true;
    }
  })

  return paramsObj;
}

8 转化为驼峰命名

var s1 = "get-element-by-id"

// 转化为 getElementById

var f = function(s) {
    return s.replace(/-\w/g, function(x) {
        return x.slice(1).toUpperCase();
    })
}

9 实现一个函数判断数据类型

function getType(obj) {
   if (obj === null) return String(obj);
   return typeof obj === 'object' 
   ? Object.prototype.toString.call(obj).replace('[object ', '').replace(']', '').toLowerCase()
   : typeof obj;
}

// 调用
getType(null); // -> null
getType(undefined); // -> undefined
getType({}); // -> object
getType([]); // -> array
getType(123); // -> number
getType(true); // -> boolean
getType('123'); // -> string
getType(/123/); // -> regexp
getType(new Date()); // -> date

10 对象数组列表转成树形结构(处理菜单)

[
    {
        id: 1,
        text: '节点1',
        parentId: 0 //这里用0表示为顶级节点
    },
    {
        id: 2,
        text: '节点1_1',
        parentId: 1 //通过这个字段来确定子父级
    }
    ...
]

转成
[
    {
        id: 1,
        text: '节点1',
        parentId: 0,
        children: [
            {
                id:2,
                text: '节点1_1',
                parentId:1
            }
        ]
    }
]
function listToTree(data) {
  let temp = {};
  let treeData = [];
  for (let i = 0; i < data.length; i++) {
    temp[data[i].id] = data[i];
  }
  for (let i in temp) {
    if (+temp[i].parentId != 0) {
      if (!temp[temp[i].parentId].children) {
        temp[temp[i].parentId].children = [];
      }
      temp[temp[i].parentId].children.push(temp[i]);
    } else {
      treeData.push(temp[i]);
    }
  }
  return treeData;
}

 

 

11 树形结构转成列表(处理菜单)

[
    {
        id: 1,
        text: '节点1',
        parentId: 0,
        children: [
            {
                id:2,
                text: '节点1_1',
                parentId:1
            }
        ]
    }
]
转成
[
    {
        id: 1,
        text: '节点1',
        parentId: 0 //这里用0表示为顶级节点
    },
    {
        id: 2,
        text: '节点1_1',
        parentId: 1 //通过这个字段来确定子父级
    }
    ...
]
function treeToList(data) {
  let res = [];
  const dfs = (tree) => {
    tree.forEach((item) => {
      if (item.children) {
        dfs(item.children);
        delete item.children;
      }
      res.push(item);
    });
  };
  dfs(data);
  return res;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

前端手写(正则、字符串、函数) 的相关文章

随机推荐

  • Task1:李宏毅深度学习P1-P2

    这次借在Datawhale组队学习的机会补全一下机器学习上一些知识的漏洞 主要是标注一下自己需要注意的地方在这与大家分享 今日分享的是李宏毅深度学习Part1 2中自己之前不太重视的地方 1 在对机器学习的各类概念介绍时 还是能看出与国内授
  • 字符串09--表示数值的字符串

    字符串09 表示数值的字符串 jz53 题目概述 解析 参考答案 注意事项 说明 题目概述 算法说明 请实现一个函数用来判断字符串是否表示数值 包括整数和小数 例如 字符串 100 5e2 123 3 1416 和 1E 16 都表示数值
  • Sublime Text 常用快捷键

    文章目录 通用 General 编辑 Editing 选择 Selecting 查找 替换 Finding Replacing 跳转 Jumping 窗口 Window 屏幕 Screen 工欲善其事 必先利其器 本文收集 Sublime
  • 解决报错:Uncaught TypeError: Cannot read properties of undefined (reading ‘install‘)

    在做vue2项目时出现如下错误 页面空白且控制台出现如下错误 报错内容 Uncaught TypeError Cannot read properties of undefined reading install at Vue use vu
  • Anaconda + jupyter notebook + jupyter lab环境配置

    1 更换源 1 1 pip源 pip config set global index url https pypi tuna tsinghua edu cn simple pip config set install trusted hos
  • SQL SERVER2008存储过程加密与解密

    前言 我们在设置数据库存储过程时经常会用到加密 如果遇到版本更新需要修改存储过程时 如果设计数据库时的存储过程没有留存 所以就必须用到存储过程的解密了 原来自己有个解密存储过程在SQL2000下应用无问题 后来升级到SQL2008后不好用了
  • 4.网络爬虫—Post请求(实战演示)

    网络爬虫 Post请求实战演示 POST请求 GET请求 POST请求和GET请求的区别 获取二进制数据 爬 百度官网 https www baidu com logo实战 发送post请求 百度翻译实战 使用session发送请求 模拟登
  • 微信小程序部署到线上环境

    微信小程序部署到线上环境 一 微信小程序申请 申请 并认证 未认证不能发布 认证需要300元 目前只支持企业认证 详细见官网说明 https mp weixin qq com cgi bin registermidpage action i
  • mac os mysql忘记root密码_mac上mysql报错以及root密码忘记解决办法

    1 对于前者ERROR 2002 HY000 Can t connect to local MySQL server through socket tmp mysql sock 2 这个错误 一般是mysql服务没开 命令行下执行sudo
  • java8的时期和时间

    文章目录 旧版日期时间的问题 新版日期时间介绍 Java util date java sql date SimpleDateFormatter calendar java8日期 DateTimeFormatter 计算 java8之前 j
  • Python学习 第五章 图形界面设计

    第五章 图形界面设计 1 常用的 Python GUI 库 1 1 Tkinter 1 2 wxPython 1 3 创建GUI程序 2 创建Windows窗口 3 几何布局管理器 3 1 pack 包装 3 2 grid 网格 3 3 p
  • leetcode移动零c++

    给定一个数组 nums 编写一个函数将所有 0 移动到数组的末尾 同时保持非零元素的相对顺序 示例 输入 0 1 0 3 12 输出 1 3 12 0 0 说明 必须在原数组上操作 不能拷贝额外的数组 尽量减少操作次数 整体思路 题目中都出
  • 软件项目经理的基本职责

    软件项目经理的基本职责 1 制定项目计划 并根据各种变化修改项目计划2 实施 项目的管理 开发 质量保证过程 确保客户的成本 进度 绩效和质量目标 3 制定有效的项目决策过程4 确保在项目生命周期中遵循是实施公司的管理和质量政策5 选择一个
  • VC++ CComboBox自绘(选择下拉列表框)

    效果图 头文件定义 CSWCheckComboBox h pragma once class CSWCheckComboBox public CComboBox DECLARE DYNAMIC CSWCheckComboBox 成员私有结构
  • gdal解析tif

    bool HandleTif ReadTif tif文件读取 std string name D XX xx tif const char charName name c str 注册 GDALAllRegister 以防中文名不能正常读取
  • Docker本地镜像推送到私有库

    Docker Registry是官方提供的工具 可以用于构建私有镜像仓库 1 下载镜像Docker Registry docker pull registy 2 运行私有库Registry 相当于本地有个私有Docker hub docke
  • 计算机基础——Excel 2010

    天软备考交流群 365218976 1 Excel 2010的基本操作 1 1 Excel的窗口界面 1 2 工作簿与工作表 1 3 单元格区域的管理 1 4 工作表的管理 1 5 输入和编辑数据 1 6 行 列和单元格的管理 1 7 批注
  • java代码引用jar包中文件的方法

    jar是一个单独的文件 里面的文件称之为资源 有两种方法获取 里面的资源文件 一般将资源文件放到resources文件夹中 1 推荐 静态和非静态方法中都能用 ClassName class getClassLoader getResour
  • 刷脸支付服务商抓住机会迎头赶上

    科技改变未来并不是一句口号 就拿买东西来讲 以前人们都是一手交钱一手交货 拿到大额的纸币 还要验真假 而现在移动支付成为主要付款方式 只要一部手机 扫一扫就能付款 一开始也有很多人不习惯手机支付 因为觉得没有现金实在 整天就是一堆数字转来转
  • 前端手写(正则、字符串、函数)

    1 实现千位分隔符 保留三位小数 parseToMoney 1234 56 return 1 234 56 parseToMoney 123456789 return 123 456 789 parseToMoney 1087654 321