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

相關文章
相關標籤/搜索