「从源码中学习」Vue源码中的JS骚操作

栏目: JavaScript · 发布时间: 7年前

内容简介:解析:使用正则去匹配 UA 中是否包含来源:
// 通过判断 `window` 对象是否存在即可
export const inBrowser = typeof window !== 'undefined'
复制代码

1.2 hasProto :检查当前环境是否可以使用对象的 __proto__ 属性

// 一个对象的 __proto__ 属性指向了其构造函数的原型
// 从一个空的对象字面量开始沿着原型链逐级检查。
export const hasProto = '__proto__' in {}
复制代码

2. user Agent 常量的一系列操作

2.1 获取当浏览器的 user Agent

// toLowerCase目的是 为了后续的各种环境检测
export const UA = inBrowser && window.navigator.userAgent.toLowerCase()
复制代码

2.2 IE浏览器判断

export const isIE = UA && /msie|trident/.test(UA)

解析:使用正则去匹配 UA 中是否包含 'msie' 或者 'trident' 这两个字符串即可判断是否为 IE 浏览器

「从源码中学习」Vue源码中的JS骚操作

来源: Internet Explorer User Agent Strings

多关键词高亮插件:Multi-highlight

2.3 IE9 | Edge | Chrome 判断

export const isIE9 = UA && UA.indexOf('msie 9.0') > 0
export const isEdge = UA && UA.indexOf('edge/') > 0
export const isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge
复制代码

3. 字符串操作

3.1 isReserved :检测字符串是否以 $ 或者 _ 开头

// charCodeAt() 方法可返回指定位置的字符的 Unicode 编码
export function isReserved (str: string): boolean {
  const c = (str + '').charCodeAt(0)
  return c === 0x24 || c === 0x5F
}
复制代码

解析:获得该字符串第一个字符的 unicode ,然后与 0x240x5F 作比较。

若作为一个想进阶中高级的前端, charCodeAt 方法的各种妙用还是需要知道的(面试算法题各种考)。

3.2 camelize : 连字符转驼峰

const camelizeRE = /-(\w)/g
export const camelize = cached((str: string): string => {
  return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
})
复制代码

解析:定义正则表达式: /-(\w)/g ,用来全局匹配字符串中 中横线及连字符后的一个字符。若捕获到,则将字符以 toUpperCase 大写替换,否则以 '' 替换。 如: camelize('aa-bb') // aaBb

3.3 toString : 将给定变量的值转换为 string 类型并返回

export function toString (val: any): string {
  return val == null
    ? ''
    : typeof val === 'object'
      ? JSON.stringify(val, null, 2)
      : String(val)
}
复制代码

解析:在 Vue 中充斥着很多这类增强型的封装,大大减少了我们代码的复杂性。但这里,我们要学习的是这种 多重三元运算符 的用法

3.3.1 多重三元运算符

export function toString (val: any): string {
  return val == null
    ? ''
    : typeof val === 'object'
      ? JSON.stringify(val, null, 2)
      : String(val)
}
复制代码

解析:

export function toString (val: any): string {
  return 当变量值为 null 时
    ? 返回空字符串
    : 否则,判断当变量类型为 object时
      ? 返回 JSON.stringify(val, null, 2)
      : 否则 String(val)
}
复制代码

3.4 capitalize :首字符大写

// 忽略cached
export const capitalize = cached((str: string): string => {
  return str.charAt(0).toUpperCase() + str.slice(1)
})
复制代码

解析: str.charAt(0) 获取 str 的第一项,利用 toUpperCase() 转换为大写字母, str.slice(1) 截取除第一项的 str 部分。

4. 类型判断

4.1 isPrimitive : 判断变量是否为原型类型

export function isPrimitive (value: any): boolean %checks {
  return (
    typeof value === 'string' ||
    typeof value === 'number' ||
    // $flow-disable-line
    typeof value === 'symbol' ||
    typeof value === 'boolean'
  )
}
复制代码

解析:这个很简单,但我们经常忽略掉 symbol 这个类型(虽然完全没用过)。

4.2 isRegExp : 判断变量是否为正则对象。

// 使用 Object.prototype.toString 与 '[object RegExp]' 做全等对比。

export function isRegExp (v: any): boolean {
  return _toString.call(v) === '[object RegExp]'
}
复制代码

这也是最准确的类型判断方法,在 Vue 中其它类型也是一样的判断

4.3 isValidArrayIndex : 判断变量是否含有效的数组索引

export function isValidArrayIndex (val: any): boolean {
  const n = parseFloat(String(val))
  // n >= 0 && Math.floor(n) === n 保证了索引是一个大于等于 0 的整数
  return n >= 0 && Math.floor(n) === n && isFinite(val)
}
复制代码

isFinite 方法检测它参数的数值。如果参数是 NaN ,正无穷大或者负无穷大,会返回 false ,其他返回 true

扩展:语法:isFinite()

「从源码中学习」Vue源码中的JS骚操作

5.Vue中的闭包骚操作

5.1 makeMap() :判断一个变量是否包含在传入字符串里

export function makeMap (
  str: string,
  expectsLowerCase?: boolean
): (key: string) => true | void {
  const map = Object.create(null)
  const list: Array<string> = str.split(',')
  for (let i = 0; i < list.length; i++) {
    map[list[i]] = true
  }
  return expectsLowerCase
    ? val => map[val.toLowerCase()]
    : val => map[val]
}
复制代码
  1. 定义一个对象 map
  2. str 分隔成数组并保存到 list 变量中
  3. 遍历 list ,并以 list 中的元素作为 mapkey ,将其设置为 true
  4. 返回一个函数,并且如果 expectsLowerCasetrue 的话,小写 map[key] :

我们用一个例子来说明下:

let isMyName = makMap('前端劝退师,帅比',true); 
//设定一个检测是否为我的名字的方法,第二个参数不区分大小写
isMyName('前端劝退师')  // true
isMyName('帅比')  // true
isMyName('丑逼')  // false
复制代码

Vue 中类似的判断非常多,也很实用。

5.1.1 isHTMLTag | isSVG | isReservedAttr

这三个函数是通过 makeMap 生成的,用来检测一个属性(标签)是否为保留属性(标签)

export const 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'
)
export const 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
)
// web平台的保留属性有 style 和 class
export const isReservedAttr = makeMap('style,class')
复制代码

5.2 once :只调用一次的函数

export function once (fn: Function): Function {
  let called = false
  return function () {
    if (!called) {
      called = true
      fn.apply(this, arguments)
    }
  }
}
复制代码

解析:以 called 作为回调标识符。调用此函数时, called 标示符改变,下次调用就无效了。也是典型的闭包调用。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Learn Python 3 the Hard Way

Learn Python 3 the Hard Way

Zed A. Shaw / Addison / 2017-7-7 / USD 30.74

You Will Learn Python 3! Zed Shaw has perfected the world’s best system for learning Python 3. Follow it and you will succeed—just like the millions of beginners Zed has taught to date! You bring t......一起来看看 《Learn Python 3 the Hard Way》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具