Vue 源码中的一些辅助函数

在回顾Vue源码的时候,常常看到Vue中一些辅助函数,总结一些平常中会用到的,和一些js代码片断html

Vue 源码中的一些辅助函数

判断对象的某个属性或者是否认义或者是否有值

function isDef (v){
 return v !== undefined && v !== null } 复制代码

已经定义的值判断是不是原始类型

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

是不是 promise 类型

function isPromise (val){
 return (  isDef(val) &&  typeof val.then === 'function' &&  typeof val.catch === 'function'  ) } 复制代码

转换为数字

// 将输入值转换为数字。若是转换失败,则返回原始字符串。
 function toNumber (val){  const n = parseFloat(val)  return isNaN(n) ? val : n } 复制代码

建立一个 map,返回一个函数去检测一个 key 值是否存在与这个 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 expectsLowerCase  ? val => map[val.toLowerCase()]  : val => map[val] }  vue 源码中的使用 var isHTMLTag = makeMap(  'html,body,base,head,link,meta,style,title,' +  'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' +  'div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,' +  'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' +  's,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' +  'embed,object,param,source,canvas,script,noscript,del,ins,' +  'caption,col,colgroup,table,thead,tbody,td,th,tr,' +  'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +  'output,progress,select,textarea,' +  'details,dialog,menu,menuitem,summary,' +  'content,element,shadow,template,blockquote,iframe,tfoot' );  var isSVG = makeMap(  'svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,' +  'foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,' +  'polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view',  true );  var isReservedTag = function (tag) {  return isHTMLTag(tag) || isSVG(tag) }; var isBuiltInTag = makeMap('slot,component', true)  function validateComponentName (name) {  if (!new RegExp(("^[a-zA-Z][\\-\\.0-9_" + (unicoderegexp.source) + "]\*\$")).test(name)) {  warn(  'Invalid component name: "' + name + '". Component names ' +  'should conform to valid custom element name in html5 specification.'  );  }  if (isBuiltInTag(name) || config.isReservedTag(name)) {  warn(  'Do not use built-in or reserved HTML elements as component ' +  'id: ' + name  );  } }  复制代码

从数组中移除一项

function remove (arr, item){
if (arr.length) {  const index = arr.indexOf(item)  if (index > -1) {  return arr.splice(index, 1)  }  } } vue 源码中的使用 Dep.prototype.removeSub = function removeSub (sub) {  remove(this.subs, sub); }; 复制代码

转换一个类数组为真实数组

function toArray (list, start){
 start = start || 0  let i = list.length - start  const ret = new Array(i)  while (i--) {  ret[i] = list[i + start]  }  return ret } vue 源码中的使用 Vue.prototype.$emit = function (event) {  const vm = this;  ...  let cbs = vm._events[event];  if (cbs) {  cbs = cbs.length > 1 ? toArray(cbs) : cbs;  const args = toArray(arguments, 1);  ...  }  return vm }; 复制代码

将属性混合到目标对象中

function extend (to, _from): Object {
 for (const key in _from) {  to[key] = _from[key]  }  return to } 复制代码

将对象数组合并为单个对象

function toObject (arr) {
 var res = {};  for (var i = 0; i < arr.length; i++) {  if (arr[i]) {  extend(res, arr[i]);  }  }  return res  }  vue 源码中的使用  function updateStyle (oldVnode: VNodeWithData, vnode: VNodeWithData) {  ...  if (Array.isArray(style)) {  style = vnode.data.style = toObject(style)  } } 复制代码

确保一个函数仅被调用一次

function once (fn) {
 var called = false;  return function () {  if (!called) {  called = true;  fn.apply(this, arguments);  }  } } vue 源码中的使用 const reject = once(reason => {  warn(  `Failed to resolve async component: ${String(factory)}` +  (reason ? `\nReason: ${reason}` : '')  );  if (isDef(factory.errorComp)) {  factory.error = true;  forceRender(true);  } });  复制代码
定义一个属性
function def (obj, key, val, enumerable) {  Object.defineProperty(obj, key, {  value: val,  enumerable: !!enumerable,  writable: true,  configurable: true  }); }  经过使用__proto__的原型链拦截来加强目标对象或数组  function protoAugment (target, src) {  target.__proto__ = src; } 经过定义来加强目标对象或数组 隐藏的属性。 function copyAugment (target, src, keys) {  for (var i = 0, l = keys.length; i < l; i++) {  var key = keys[i];  def(target, key, src[key]);  } } vue 源码中的使用 export class Observer {  value: any;  dep: Dep;  vmCount: number;  constructor (value: any) {  this.value = value  this.dep = new Dep()  this.vmCount = 0  def(value, '__ob__', this)  if (Array.isArray(value)) {  if (hasProto) {  protoAugment(value, arrayMethods)  } else {  copyAugment(value, arrayMethods, arrayKeys)  }  this.observeArray(value)  } else {  this.walk(value)  }  }  ... } 复制代码

平常使用的js代码片断

取数组相同项(不一样项同理取不包含)

选择一个数组建立  Set,而后使用  Array.filter()  过滤 Set 中包含的另外一个数组值vue

const intersection = (ary1, ary2) => { const s = new Set(ary2); return ary1.filter(item => s.has(item)) };
//若是肯定数组中不会有重复部分 const intersection = (ary1, ary2) => ary1.filter(v => ary2.includes(v)); // intersection([32,43,543], [32,12,55,43]) -> [32,43] 复制代码

统计数组中出现指定值的次数

用 reduce 查询数组,符合条件时+1html5

const countOccurrences = (ary, value) => ary.reduce((res, val) => val === value ? ++res : res + 0, 0);
//countOccurrences([2,4,11,'a','a','b',32], 'a') -> 2 复制代码

扁平化数组(扁平全部)

递归数组,reduce 展开数组并合并node

const deepFlatten = arr => arr.reduce((a, v) => a.concat(Array.isArray(v) ? deepFlatten(v) : v), []);
// deepFlatten(['a',['b'],[['c'],'d']]) -> ['a','b','c','d'] //若是所要展开的只有一层 能够直接使用 es6 的 Array.flat(),且只能展开一层 ['a',['b'],['c'],'d'].flat() -> ['a','b','c','d']'a',['b'],[['c'],'d']].flat() -> ["a", "b", ['c'], "d"] 复制代码

扁平化指定深度的数组

在上一个的基础上改造一下,增长一个深度参数es6

const flattenDepth = (ary, depth = 1) =>
depth != 1 ? ary.reduce((a, v) => a.concat(Array.isArray(v) ? flattenDepth(v, depth - 1) : v), []) : ary.flat(); // flattenDepth(['a','b',['c'],[['d','e',['f'] ]]], 2) -> ["a", "b", "c", "d", "e", ['f']] 复制代码

滚动到顶部

const scrollToTop = _ => {
const c = document.documentElement.scrollTop || document.body.scrollTop; //获取到顶端的距离 if (c > 0) {  window.requestAnimationFrame(scrollToTop);//滚动动画效果  window.scrollTo(0, c - c / 8); } }; 复制代码

取两个日期之间相差的天数

const getDaysDiffBetweenDates = (beginDate, endDate) => ( endDate - beginDate) / (1000 _ 3600 _ 24);
// getDaysDiffBetweenDates(new Date("2020-09-22"), new Date("2020-10-01")) -> 9 复制代码

本文使用 mdnice 排版canvas

相关文章
相关标签/搜索