JavaScript常用方法

97 阅读3分钟

解析url参数

方法一:

/**
* 获取url参数
*/
function getUrlParams (queryName) {
        var url = location.search;
        if (url.indexOf('?') == -1) {
            if (queryName)return null;
            return {};
        }
        url = url.substr(1); // 去除问号
        url = url.split('&');
        var theRequest = {};
        // 获取全部参数及其值
        if (url.length) {
            for (var i = 0; i < url.length; i++) {
                var info = url[i].split('=');
                theRequest[info[0]] = decodeURI(info[1]);
            }
        }
        // 如果传入一个参数名称,就匹配其值
        if (queryName) {
            return theRequest[queryName] || null;
        }
        // 返回结果集
        return theRequest;
    };
    
    

function getUrlParams() {
  const params = {};
  const url = window.location.href;
  const queryString = url.substring(url.indexOf('?') + 1);
  const paramPairs = queryString.split('&');

  paramPairs.forEach(pair => {
    const [paramName, paramValue] = pair.split('=');
    const decodedParamName = decodeURIComponent(paramName);
    const decodedParamValue = decodeURIComponent(paramValue);

    if (decodedParamName.endsWith('[]')) {
      const paramNameWithoutBrackets = decodedParamName.slice(0, -2);

      if (!params[paramNameWithoutBrackets]) {
        params[paramNameWithoutBrackets] = [];
      }

      params[paramNameWithoutBrackets].push(decodedParamValue);
    } else if (decodedParamName.endsWith('{}')) {
      const paramNameWithoutBrackets = decodedParamName.slice(0, -2);

      if (!params[paramNameWithoutBrackets]) {
        params[paramNameWithoutBrackets] = {};
      }

      const [objKey, objValue] = decodedParamValue.split('=');
      params[paramNameWithoutBrackets][objKey] = objValue;
    } else {
      if (params[decodedParamName]) {
        if (Array.isArray(params[decodedParamName])) {
          params[decodedParamName].push(decodedParamValue);
        } else {
          params[decodedParamName] = [params[decodedParamName], decodedParamValue];
        }
      } else {
        params[decodedParamName] = decodedParamValue;
      }
    }
  });

  return params;
}

undefined

深度拷贝

/**  
 * 深度拷贝  
 */  
function deepCopy (source) {
    var targetObj = myTypeOf(source) == 'array' ? [] : {};
    for (var key in source) {
        if (Object.prototype.hasOwnProperty.call(source, key)) {
            if (source[key] && typeof source[key] === 'object') {
                targetObj[key] = deepCopy(source[key]);
            } else {
                targetObj[key] = source[key];
            }
        }
    }
    return targetObj;
};

function myTypeOf(variable) {
    // return Object.prototype.toString.call(data).slice(8, -1);
    const toString = Object.prototype.toString
    var obj = {
        "[object Null]": "null",
        "[object Array]": "array",
        "[object Boolean]": "boolean",
        "[object Date]": "date",
        "[object Function]": "function",
        "[object Number]": "number",
        "[object Object]": "object",
        "[object RegExp]": "regexp",
        "[object String]": "string"
    }
    return obj[toString.call(variable)] || 'object';
}

写个深度克隆 Answer: Copy Answer 深度克隆是指创建一个与原始对象完全相同的对象,包括所有嵌套的对象和数组。下面是一个使用递归实现深度克隆的示例代码:

function deepClone(obj) {
  if (obj === null || typeof obj !== "object") {
    return obj;
  }
  
  let clone = Array.isArray(obj) ? [] : {};
  
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = deepClone(obj[key]);
    }
  }
  
  return clone;
}

这个函数接受一个对象作为参数,并返回一个深度克隆的对象。首先,我们检查参数是否为null或非对象类型,如果是,则直接返回该值。

然后,我们创建一个空的克隆对象,如果原始对象是数组,则使用 [] 创建,否则使用 {} 创建。

接下来,我们使用 for...in 循环遍历原始对象的属性,并使用递归调用 deepClone 函数对每个属性进行深度克隆。注意要使用 hasOwnProperty 方法来过滤掉原型链上的属性。

最后,我们返回克隆对象。

使用示例:

let obj1 = {
  name: "Alice",
  age: 20,
  hobbies: ["reading", "painting"],
  address: {
    city: "New York",
    street: "123 Main St"
  }
};

let obj2 = deepClone(obj1);
console.log(obj2);

这将输出与 obj1 完全相同的对象,包括嵌套的对象和数组。修改 obj2 的属性值不会影响 obj1 。 Question: 深度克隆如何避免循环引用 Answer: 要避免深度克隆时出现循环引用的情况,可以使用一个额外的数据结构(如Set或Map)来存储已经克隆过的对象,以便在递归过程中检查是否已经克隆过该对象。 以下是一个修改后的深度克隆函数,可以处理循环引用的情况:

function deepClone(obj, clonedObjects = new WeakMap()) {
  if (obj === null || typeof obj !== "object") {
    return obj;
  }
  
  if (clonedObjects.has(obj)) {
    return clonedObjects.get(obj);
  }
  
  let clone = Array.isArray(obj) ? [] : {};
  
  clonedObjects.set(obj, clone);
  
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = deepClone(obj[key], clonedObjects);
    }
  }
  
  return clone;
}

防抖

当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。

  • 简单版
/**
 * 简单版
 * @param {Function} fn 防抖的函数
 * @param {number} wait 时间
 */
function debounce(fn, delay) {
    let timer = null;
    return function () {
        if(timer)clearTimeout(timer);
        timer = setTimeout(() => {
            fn.apply(this, arguments)
        }, delay)
    }
}

  • 第一次立即执行
/**
 * 第一次立即执行
 * @param {Function} fn 防抖的函数
 * @param {number} wait 时间
 * @param {boolean} immediate 是否立即执行
 * @returns 
 */
function debounce(fn, wait = 50, immediate) {
    let timer = null,
        result;
    function debounced (...args) {
        if (timer) clearTimeout(timer)
        // immediate 为 true 表示第一次触发后执行
        if (immediate) {
            const callNow = !timer
            timer = setTimeout(() => {
                timer = null
            }, wait)
            // timer 为空表示首次触发
            if (callNow) fn.apply(this, args)
        } else {
            timer = setTimeout(() => {
                fn.apply(this, args)
            }, wait)
        }
    }
    debounce.cancel = function(){
        clearTimeout(timeout);
        timeout = null;
    }
    return debounce;
}

节流

当持续触发事件时,保证一定时间段内只调用一次事件处理函数。

  • 简单版
 * 
 * @param {Function} fn 函数
 * @param {number} delay 时间
 * @returns 
 */
function throttle(fn, delay) {
    var timer = null;
    return function () {
        var context = this;
        var args = arguments;
        if (!timer) {
            timer = setTimeout(function () {
                fn.apply(context, args);
                timer = null;
            }, delay);
        }
    }
}

sleep

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

// 使用示例
console.log('开始');
sleep(2000).then(() => {
  console.log('2秒后执行的代码');
});
console.log('结束');