一些常用的代码块,

JS Snippets

// isObject
function isObject (obj) {
  return obj !== null && typeof obj === 'object'
}

// 判断数据是数字,可能类型是string,但是'123'也算数字
function isNumber(value) {
  return !isNaN(Number(value));
}

// isEmpty
const isEmpty = value => {
  return value === undefined || value === null ||
    (typeof value === "object" && Object.keys(value).length === 0) ||
    (typeof value === "string" && value.trim().length === 0)
}

↑ Back to Top

如何判断一个对象是否为数组

如果浏览器支持 Array.isArray()可以直接判断, 否则需进行必要判断

/**
 * 判断一个对象是否是数组,参数不是对象或者不是数组,返回false
 *
 * @param {Object} arg 需要测试是否为数组的对象
 * @return {Boolean} 传入参数是数组返回true,否则返回false
 */
function isArray(arg) {
  if (typeof arg === 'object') {
    return Object.prototype.toString.call(arg) === '[object Array]';
  }
  return false;
}

↑ Back to Top

如何判断一个对象是否为函数

/**
 * 判断对象是否为函数,如果当前运行环境对可调用对象(如正则表达式)
 * 的typeof返回'function',采用通用方法,否则采用优化方法
 *
 * @param {Any} arg 需要检测是否为函数的对象
 * @return {boolean} 如果参数是函数,返回true,否则false
 */
function isFunction(arg) {
  if (arg) {
    if (typeof (/./) !== 'function') {
      return typeof arg === 'function';
    } else {
      return Object.prototype.toString.call(arg) === '[object Function]';
    }
  } // end if
  return false;
}

↑ Back to Top

深度克隆函数 deepClone

function deepClone(obj) {
  var _toString = Object.prototype.toString;

  // null, undefined, non-object, function
  if (!obj || typeof obj !== 'object') {
    return obj;
  }

  // DOM Node
  if (obj.nodeType && 'cloneNode' in obj) {
    return obj.cloneNode(true);
  }

  // Date
  if (_toString.call(obj) === '[object Date]') {
    return new Date(obj.getTime());
  }

  // RegExp
  if (_toString.call(obj) === '[object RegExp]') {
    var flags = [];
    if (obj.global) { flags.push('g'); }
    if (obj.multiline) { flags.push('m'); }
    if (obj.ignoreCase) { flags.push('i'); }

    return new RegExp(obj.source, flags.join(''));
  }

  var result = Array.isArray(obj) ? [] :
    obj.constructor ? new obj.constructor() : {};

  for (var key in obj ) {
    result[key] = deepClone(obj[key]);
  }

  return result;
}

function A() {
  this.a = a;
}

var a = {
  name: 'qiu',
  birth: new Date(),
  pattern: /qiu/gim,
  container: document.body,
  hobbys: ['book', new Date(), /aaa/gim, 111]
};

var c = new A();
var b = deepClone(c);
console.log(c.a === b.a);
console.log(c, b);

↑ Back to Top

编写一个函数接受 url 中 query string 为参数,返回解析后的 Object,query string 使用 application/x-www-form-urlencoded 编码

/**
 * 解析query string转换为对象,一个key有多个值时生成数组
 *
 * @param {String} query 需要解析的query字符串,开头可以是?,
 * 按照application/x-www-form-urlencoded编码
 * @return {Object} 参数解析后的对象
 */
function parseQuery(query) {
  var result = {};

  // 如果不是字符串返回空对象
  if (typeof query !== 'string') {
    return result;
  }

  // 去掉字符串开头可能带的?
  if (query.charAt(0) === '?') {
    query = query.substring(1);
  }

  var pairs = query.split('&');
  var pair;
  var key, value;
  var i, len;

  for (i = 0, len = pairs.length; i < len; ++i) {
    pair = pairs[i].split('=');
    // application/x-www-form-urlencoded编码会将' '转换为+
    key = decodeURIComponent(pair[0]).replace(/\+/g, ' ');
    value = decodeURIComponent(pair[1]).replace(/\+/g, ' ');

    // 如果是新key,直接添加
    if (!(key in result)) {
      result[key] = value;
    }
    // 如果key已经出现一次以上,直接向数组添加value
    else if (isArray(result[key])) {
      result[key].push(value);
    }
    // key第二次出现,将结果改为数组
    else {
      var arr = [result[key]];
      arr.push(value);
      result[key] = arr;
    } // end if-else
  } // end for

  return result;
}

function isArray(arg) {
  if (arg && typeof arg === 'object') {
    return Object.prototype.toString.call(arg) === '[object Array]';
  }
  return false;
}
/**
console.log(parseQuery('sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8'));
 */

解析一个完整的 url,返回 Object 包含域与 window.location 相同

/**
 * 解析一个url并生成window.location对象中包含的域
 * location:
 * {
 *      href: '包含完整的url',
 *      origin: '包含协议到pathname之前的内容',
 *      protocol: 'url使用的协议,包含末尾的:',
 *      username: '用户名', // 暂时不支持
 *      password: '密码',  // 暂时不支持
 *      host: '完整主机名,包含:和端口',
 *      hostname: '主机名,不包含端口'
 *      port: '端口号',
 *      pathname: '服务器上访问资源的路径/开头',
 *      search: 'query string,?开头',
 *      hash: '#开头的fragment identifier'
 * }
 *
 * @param {string} url 需要解析的url
 * @return {Object} 包含url信息的对象
*/
function parseUrl(url) {
  var result = {};
  var keys = ['href', 'origin', 'protocol', 'host',
              'hostname', 'port', 'pathname', 'search', 'hash'];
  var i, len;
  var regexp = /(([^:]+:)\/\/(([^:\/\?#]+)(:\d+)?))(\/[^?#]*)?(\?[^#]*)?(#.*)?/;

  var match = regexp.exec(url);

  if (match) {
    for (i = keys.length - 1; i >= 0; --i) {
      result[keys[i]] = match[i] ? match[i] : '';
    }
  }

  return result;
}

完成函数 getViewportSize 返回指定窗口的视口尺寸

/**
* 查询指定窗口的视口尺寸,如果不指定窗口,查询当前窗口尺寸
**/
function getViewportSize(w) {
  w = w || window;

  // IE9及标准浏览器中可使用此标准方法
  if ('innerHeight' in w) {
    return {
      width: w.innerWidth,
      height: w.innerHeight
    };
  }

  var d = w.document;
  // IE 8及以下浏览器在标准模式下
  if (document.compatMode === 'CSS1Compat') {
    return {
      width: d.documentElement.clientWidth,
      height: d.documentElement.clientHeight
    };
  }

  // IE8及以下浏览器在怪癖模式下
  return {
    width: d.body.clientWidth,
    height: d.body.clientHeight
  };
}

完成函数 getScrollOffset 返回窗口滚动条偏移量

/**
 * 获取指定window中滚动条的偏移量,如未指定则获取当前window
 * 滚动条偏移量
 *
 * @param {window} w 需要获取滚动条偏移量的窗口
 * @return {Object} obj.x为水平滚动条偏移量,obj.y为竖直滚动条偏移量
 */
function getScrollOffset(w) {
  w =  w || window;
  // 如果是标准浏览器
  if (w.pageXOffset != null) {
    return {
      x: w.pageXOffset,
      y: w.pageYOffset
    };
  }

  // 老版本IE,根据兼容性不同访问不同元素
  var d = w.document;
  if (d.compatMode === 'CSS1Compat') {
    return {
      x: d.documentElement.scrollLeft,
      y: d.documentElement.scrollTop
    }
  }

  return {
    x: d.body.scrollLeft,
    y: d.body.scrollTop
  };
}

↑ Back to Top

// 费波拉希数列
function fib(n) {
  return function(n, a, b) {
    return n > 0 ? arguments.callee(n - 1, b, a + b) : a;
  } (n, 0, 1);
}

// 

↑ Back to Top

// 第 114 题:编程题,找出字符串中连续出现最多的字符和个数
// 'abcaakjbb' => {'a':2,'b':2}
// 'abbkejsbcccwqaa' => {'c':3}
const arr = str.match(/(\w)\1*/g);
const maxLen = Math.max(...arr.map(s => s.length));
const result = arr.reduce((pre, curr) => {
  if (curr.length === maxLen) {
    pre[curr[0]] = curr.length;
  }
  return pre;
}, {});

console.log(result);

↑ Back to Top

有一个大数组,var a = [‘1’, ‘2’, ‘3’, …];a 的长度是 100,内容填充随机整数的字符串.请先构造此数组 a,然后设计一个算法将其内容去重

/**
  * 数组去重
  **/
  function normalize(arr) {
    if (arr && Array.isArray(arr)) {
      var i, len, map = {};
      for (i = arr.length; i >= 0; --i) {
        if (arr[i] in map) {
          arr.splice(i, 1);
        } else {
          map[arr[i]] = true;
        }
      }
    }
    return arr;
  }

  /**
  * 用100个随机整数对应的字符串填充数组。
  **/
  function fillArray(arr, start, end) {
    start = start == undefined ? 1 : start;
    end = end == undefined ?  100 : end;

    if (end <= start) {
      end = start + 100;
    }

    var width = end - start;
    var i;
    for (i = 100; i >= 1; --i) {
      arr.push('' + (Math.floor(Math.random() * width) + start));
    }
    return arr;
  }

  var input = [];
  fillArray(input, 1, 100);
  input.sort(function (a, b) {
      return a - b;
  });
  console.log(input);

  normalize(input);
  console.log(input);

↑ Back to Top

// 116
1 + "1" // 11
2 * "2" // 4
[1, 2] + [2, 1] // "1,22,1"
"a" + + "b" // aNaN

1 + "1"
// 加性操作符:如果只有一个操作数是字符串,则将另一个操作数转换为字符串,然后再将两个字符串拼接起来所以值为:“11”

2 * "2"
// 乘性操作符:如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值

[1, 2] + [2, 1]
// Javascript中所有对象基本都是先调用valueOf方法,如果不是数值,再调用toString方法。
// 所以两个数组对象的toString方法相加,值为:"1,22,1"

"a" + + "b"
// 后边的“+”将作为一元操作符,如果操作数是字符串,将调用Number方法将该操作数转为数值,如果操作数无法转为数值,则为NaN。
// 所以值为:"aNaN"

// 以上均参考:《Javascript高级程序设计》

↑ Back to Top

Js new Date()方法移动端兼容 ios

//直接:安卓可兼容两种格式,ios支持/** 2019/11/09 10:13:21 **/格式
let str = '2019-11-09 10:13:21'; // 这种格式 ios不兼容使用new date() >==> NaN
  str = str.replace(/\-/g, "/"); // 兼容ios '2019/11/09 10:13:21'
let iosstr = '2019/11/09 10:13:21'; // 兼容ios写法