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

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

内容简介:解析:使用正则去匹配 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 标示符改变,下次调用就无效了。也是典型的闭包调用。


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

查看所有标签

猜你喜欢:

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

深入理解C#(第3版)

深入理解C#(第3版)

斯基特 (Jon Skeet) / 姚琪琳 / 人民邮电出版社 / 2014-4-1 / 99.00元

本书是世界顶级技术专家“十年磨一剑”的经典之作,在C#和.NET领域享有盛誉。与其他泛泛介绍C#的书籍不同,本书深度探究C#的特性,并结合技术发展,引领读者深入C#的时空。作者从语言设计的动机出发,介绍支持这些特性的核心概念。作者将新的语言特性放在C#语言发展的背景之上,用极富实际意义的示例,向读者展示编写代码和设计解决方案的最佳方式。同时作者将多年的C#开发经验与读者分享,读者可咀其精华、免走弯......一起来看看 《深入理解C#(第3版)》 这本书的介绍吧!

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

URL 编码/解码

SHA 加密
SHA 加密

SHA 加密工具

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

在线XML、JSON转换工具