【若川视野 x 源码共读】第24期 | vue2工具函数

142 阅读3分钟

本文参加了由公众号@若川视野发起的每周源码共读活动,点击了解详情一起参与。 这是源码共读的第 24 期,链接:juejin.cn/post/707976…

前言

参与源码共读,让我们成为更好的自己~

1.工具函数

项目地址,文件路径:vue/src/shared/util

1.1 冻结对象

freezeObject = Object.freeze({});

1.2 是否未定义

function isUndef(value) {
  return value === 'undefined || value === null;
}

1.3 是否已定义

function isDef(value) {
  return value !== undefined && value !== null;
}

1.4 是否为true

function isTrue(value) {
  return value === true;
}

1.5 是否为false

function isFalse(value) {
  return value === false;
}

1.6 是否为原始值(number,string,symbol,boolean)

function isPrimitive(value) {
  return (
    typeof value === 'string' ||
    typeof value === 'number' ||
    typeof value === 'boolean' ||
    typeof value === 'symbol'
  )
}

1.7 是否为Object

function isObject(value) {
  return value !== null && typeof value === 'object';
}

1.8 是否为false

function isFalse(value) {
  return value === false;
}

1.9 转原始类型

_toString = Object.prototype.toString;

function toRawType(value) {
  return _toString.call(value).slice(8, -1);
}

1.10 是否为纯对象

function isPlainObject(value) {
  return _toString.call(value) === '[object object]';
}

1.11 是否为正则表达式

function isRegExp(value) {
  return _toString.call(value) === '[object, RegExp]';
}

1.12 是否为可用数组索引值

function isValidArrayIndex(value) {
  const n = parseFloat(value);
  return n >= 0 && Math.floor(n) === n && isFinite(value);
}

parseFloat()方法返回一个浮点数。mdn

isFinite()方法判断是否为有限数值。mdn

1.13 是否是Promise

function isPromise(value) {
  return isDef(value) &&
    typeof value.then === 'function' &&
    typeof value.catch === 'function'
}

1.14 toString转字符串

function toString(value) {
  return value == null ?
    '' :
    Array.isArray(value) || isPlainObject(value) || value.toString === _toString ?
    JSON.stringify(value, null, 2) :
    String(value);
}

JSON.stringify(value, [replacer], [space]) mdn

1.15 toNumber转数字

function toNumber(value) {
  const num = parseFloat(value);
  
  return isNaN(num) ? value : num;
}

parseFloat:  函数解析一个参数(必要时先转换为字符串)并返回一个浮点数。

1.16 makeMap生成一个Map

function makeMap(str, expectsLowerCase) {
  const map = Object.create(null);
  const list = str.split(',');
  
  for(let i = 0; i < list.length; i++) {
    map[list[i]] = true;
  }
  
  return expects ? val => map[val.toLowCase()] : val => map[val];
}

传入一个用 , 分隔的字符串生成一个map,返回一个函数查看key是否存在于map中。

1.17 remove

移除数组中的一项

function remove(array, item) {
  const len = array.length;
  
  if(len) {
    if(item === array[len - 1]) {
      array.length = len - 1;
      return;
    }
  }
  
  const index = array.indexOf(item);
  
  if(index > -1) {
    return array.slice(index, 1);
  }
}

1.18 hasOwn

检查是否是自己的属性

const hasOwnProperty = Object.prototype.hasOwnProperty

function hasOwn(obj, key) {
  return hasOwnProperty.call(obj, key);
}

1.19 cached

检查是否是自己的属性

function cached(fn) {
  const cache = Object.create(null);
  
  return function(s) {
    const h = cache[s];
    
    return h || (cache[s] = fn(s));
  }
}

1.20 camelizeRe

连字符转小驼峰

const camelizeRe = /-(\w)/g;

const camelize = cached((str) => {
  return str.replace(camelizeRe, (_, s) => s ? s.toUpperCase() : '')
})

1.21 capitalize

首字母转大写

const capitalize = cached((str) => {
  return str.charAt(0).toUpperCase() + str.slice(1);
})

1.22 hyphenate

连字符转小驼峰

const hyphenateRE = /\B(A-Z)/g;

const hyphenate = cached((str) => {
  return str.replace(hyphenateRE, '-$1').toLowerCase();
})

1.23 polyfillBind

function polyfillBind(fn, ctx) {
  function boundFn(v) {
  const len = arguments.length;
  
  return len ?
    len > 1 ?
    fn.apply(ctx, arguments) :
    fn.call(ctx, v) :
    fn.call(ctx);
  }
  
  boundFn._length = fn.length;
  return boundFn;
}

const nativeBind(fn, ctx) {
  return fn.bind(ctx);
}

const bind = Function.prototype.bind ? nativeBind : polyfillBind;

1.24 toArray

function toArray(list, start = 0) {
  let i = list.length - start;
  const result = new Array(i);
  
  while(--i) {
    result[i] = list[i + start];
  }
  
  return result;
}

1.25 extend

合并对象

function extend(to, from) {
  for(const i in from) {
    to[i] = from[i];
  }
  
  return to;
}

1.26 toObject

function toObject(arr) {
  const obj = {};
  
  for(let j = 0; j < arr.length; j++) {
    if(arr[j]) {
      extends(obj, arr[j]);
    }
  }
  
  return obj;
}

1.27 noop

function noop(a, b, c) { };

1.28 no

const no = (a, b, c) => false;

1.29 identity

const identity = (a) => return a;

1.30 genStaticKeys

function genStaticKeys(arr) {
  return arr
  .reduce((pre, cur) => pre.concat(cur.staticKeys), [])
  .join(',');
};

1.31 looseEqual

宽松相等

function looseEqual(a, b) {
  if(a === b) {
    return true;
  }
  
  const isObjectA = isObject(a);
  const isObjectB = isObject(b);
  
  if(isObjectA && isObjectB) {
    try {
      const isArrayA = isArray(a);
      const isArrayB = isArray(b);
      
      if(isArrayA && isArrayB) {
        return (
          a.length === b.length &&
          a.every((ele, ids) => looseEqual(ele, b[ids]));
        )
      } else if(a instanceof Date && b instanceof Date) {
        return a.getTime() === b.getTime();
      } else if(!isArrayA && !isArrayB) {
        const keyA = Object.keys(a);
        const keyB = Object.keys(b);
        
        return (
          keyA.length === keyB.length &&
          keyA.every((ele) => looseEqual(a[ele], b[ele]));
        )
      } else {
        return false;
      }
    } catcth(e) {
      return false;
    }
  } else if(!isObjectA && !isObjectB) {
    return String(a) === String(b);
  } else {
    return false;
  }
};

1.32 looseIndexOf

原生indexOf匹配为严格相等

function looseIndexOf(arr, value) {
  for(let j = 0; j < arr.length; j++) {
    if(looseEqual(arr[j], value)) {
      return j;
    }
  }
  
  return -1;
}

1.33 once

利用闭包使函数只能调用一次

function once(fn) {
  let called = false;
  
  return function() {
    if(!called) {
      called = true;
      fn.apply(this, arguments);
    }
  }
}

总结

这期源码大部分都能理解看懂,但是部分工具函数在工作中没有实际运用过,就当巩固基础查缺补漏啦,继续加油~