资讯专栏INFORMATION COLUMN

VueJS源码学习——工具类函数实现

adam1q84 / 1823人阅读

摘要:原文地址项目地址上一篇遗留的作为版本频繁使用的,在构造函数里以引入类实现了多种过滤方法包括方法的实现其实是对的对象的方法做了一层封装,有意思的是发现发现方法的第二参数和第三个参数,查了才知道后两个参数分别代表要提取的属性以及缩进格式,在这里

原文地址
项目地址

上一篇遗留的 filter

作为 1.0 版本频繁使用的 filter,在 构造函数里以 Vue.Options.filters 引入:

...
import filters from "./filters/index"
...

Vue.version = "1.0.8"
...
Vue.options = {
  directives,
  elementDirectives,
  filters,
  transitions: {},
  components: {},
  partials: {},
  replace: true
}

export default Vue

...

filter 类实现了多种过滤方法,包括

orderBy

filterBy

limitBy

json

capitalize

uppercase

lowercase

currency

pluralize

debounce

JSON
  json: {
    read: function (value, indent) {
      return typeof value === "string"
        ? value
        : JSON.stringify(value, null, Number(indent) || 2)
    },
    write: function (value) {
      try {
        return JSON.parse(value)
      } catch (e) {
        return value
      }
    }
  },

json 方法的实现其实是对 js 的 JSON 对象的方法做了一层封装, 有意思的是发现 JSON.stringify(value, null, Number(indent) || 2), 发现 stringify 方法的第二参数和第三个参数,查了mdn 才知道后两个参数分别代表要提取的属性以及缩进格式,在这里是提取所有属性并以两个空格作为缩进,而且有趣的是这个方法会忽略值为 undefined 或者 function 的属性,如果值为数组且数组里面有 undefined 或者 function,则转换为 null,更多特性请参考MDN文档

currency
  const digitsRE = /(d{3})(?=d)/g
  /**
   * 12345 => $12,345.00
   *
   * @param {String} sign
   */

  currency (value, currency) {
    value = parseFloat(value)
    if (!isFinite(value) || (!value && value !== 0)) return ""
    currency = currency != null ? currency : "$"
    var stringified = Math.abs(value).toFixed(2)
    var _int = stringified.slice(0, -3)
    var i = _int.length % 3
    var head = i > 0
      ? (_int.slice(0, i) + (_int.length > 3 ? "," : ""))
      : ""
    var _float = stringified.slice(-3)
    var sign = value < 0 ? "-" : ""
    return currency + sign + head +
      _int.slice(i).replace(digitsRE, "$1,") +
      _float
  }

currency用于数字格式化, 实现亮点在于 digitsRE 这个正则表达式,它使用了 ?=(正向预查)来匹配连续三个数字且后续一个字符还是数字的情况

export function filterBy (arr, search, delimiter) {
  arr = convertArray(arr)
  if (search == null) {
    return arr
  }
  if (typeof search === "function") {
    return arr.filter(search)
  }
  // cast to lowercase string
  search = ("" + search).toLowerCase()
  // allow optional `in` delimiter
  // because why not
  var n = delimiter === "in" ? 3 : 2
  // extract and flatten keys
  var keys = toArray(arguments, n).reduce(function (prev, cur) {
    return prev.concat(cur)
  }, [])
  var res = []
  var item, key, val, j
  for (var i = 0, l = arr.length; i < l; i++) {
    item = arr[i]
    val = (item && item.$value) || item
    j = keys.length
    if (j) {
      while (j--) {
        key = keys[j]
        if ((key === "$key" && contains(item.$key, search)) ||
            contains(getPath(val, key), search)) {
          res.push(item)
          break
        }
      }
    } else if (contains(item, search)) {
      res.push(item)
    }
  }
  return res
}

filterBy 功能的实现值得一看

工具类 util
export * from "./lang"
export * from "./env"
export * from "./dom"
export * from "./options"
export * from "./component"
export * from "./debug"
export { defineReactive } from "../observer/index"

util 实现了很多工具类的方法供 vue 使用,属于底层且非业务逻辑的代码实现,因此应该是比较好理解的一个模块

util/lang.js set 方法

lang 实现的第一个方法是 set(obj, key, val), 不过和理解的不同,工具类方法的实现是可能包含业务逻辑的,set 会为 object 的某个属性设置新的值,并且如果属性不存在,会触发通知

export function set (obj, key, val) {
  if (hasOwn(obj, key)) { // 如果存在这个属性,直接更新该值并返回
    obj[key] = val
    return
  }
  if (obj._isVue) { // 如果是 vue 对象,则更新 obj 为 obj._data
    set(obj._data, key, val)
    return
  }
  var ob = obj.__ob__  // 不存在该属性时,获取 obj 的 __ob__ 属性值
  if (!ob) { // 不存在时直接更新返回
    obj[key] = val
    return
  }
  ob.convert(key, val) // 存在的话调用 convert 函数
  ob.dep.notify() // 这里应该就是触发更新通知吧
  if (ob.vms) { // vms 暂时不知道是什么
    var i = ob.vms.length
    while (i--) {
      var vm = ob.vms[i]
      vm._proxy(key)
      vm._digest()
    }
  }
}

var hasOwnProperty = Object.prototype.hasOwnProperty
/**
 * Check whether the object has the property.
 *
 * @param {Object} obj
 * @param {String} key
 * @return {Boolean}
 */
export function hasOwn (obj, key) {
  return hasOwnProperty.call(obj, key)
}

hasOwnProperty 用来检测对象是否含有某个属性,不包括继承的,为了避免 hasOwnProperty 被重写,最好使用 Object.prototype.hasOwnProperty.call(obj, key) 的方式来调用

del(obj,key) 用来删除相关的属性也是类似的操作

isLiteral
/**
 * Check if an expression is a literal value.
 *
 * @param {String} exp
 * @return {Boolean}
 */

var literalValueRE = /^s?(true|false|[d.]+|"[^"]*"|"[^"]*")s?$/
export function isLiteral (exp) {
  return literalValueRE.test(exp)
}

暂时不知道是用在哪里,从正则表达式看来是匹配一段文本字符串

_toString

_toString 函数确保值为 null 或为 undefinded 输出为空字符串, 这里利用的模糊等号 "==" 来匹配 null 和 undefined:

export function _toString (value) {
  return value == null
    ? ""
    : value.toString()
}
camelize(驼峰) 和 hyphenate(连字符)
var camelizeRE = /-(w)/g
export function camelize (str) {
  return str.replace(camelizeRE, toUpper)
}

function toUpper (_, c) {
  console.log(arguments);
  return c ? c.toUpperCase() : ""
}

var hyphenateRE = /([a-zd])([A-Z])/g
export function hyphenate (str) {
  return str
    .replace(hyphenateRE, "$1-$2")
    .toLowerCase()
}
/**
 * Converts hyphen/underscore/slash delimitered names into
 * camelized classNames.
 *
 * e.g. my-component => MyComponent
 *      some_else    => SomeElse
 *      some/comp    => SomeComp
 *
 * @param {String} str
 * @return {String}
 */

var classifyRE = /(?:^|[-_/])(w)/g // 使用了非获取匹配
export function classify (str) {
  return str.replace(classifyRE, toUpper)
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85092.html

相关文章

  • VueJS源码学习——工具函数实现(二)

    摘要:它被当做一个轻量版本的使用,用于存储已排好版的或尚未打理好格式的片段。最大的区别是因为不是真实树的其中一部分,它的变化不会引起树的重新渲染的操作,或者导致性能影响的问题出现。 原文地址项目地址 工具类 /** * Simple bind, faster than native * * @param {Function} fn * @param {Object} ctx * @...

    fish 评论0 收藏0
  • VueJS源码学习——项目结构&目录

    摘要:所以整个的核心,就是如何实现这三样东西以上摘自囧克斯博客的一篇文章从版本开始这个时候的项目结构如下源码在里面,为打包编译的代码,为打包后代码放置的位置,为测试代码目录。节点类型摘自资源另一位作者关于源码解析 本项目的源码学习笔记是基于 Vue 1.0.9 版本的也就是最早的 tag 版本,之所以选择这个版本,是因为这个是最原始没有太多功能拓展的版本,有利于更好的看到 Vue 最开始的骨...

    ad6623 评论0 收藏0
  • Vue.js资源分享

    摘要:中文官网英文官网组织发出一个问题之后,不要暂时的离开电脑,如果没有把握先不要提问。珍惜每一次提问,感恩每一次反馈,每个人工作还是业余之外抽出的时间有限,充分准备好应有的资源之后再发问,有利于问题能够高效质量地得到解决。 Vue.js资源分享 更多资源请Star:https://github.com/maidishike... 文章转自:https://github.com/maid...

    vpants 评论0 收藏0
  • 前端资源系列(4)-前端学习资源分享&前端面试资源汇总

    摘要:特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 本以为自己收藏的站点多,可以很快搞定,没想到一入汇总深似海。还有很多不足&遗漏的地方,欢迎补充。有错误的地方,还请斧正... 托管: welcome to git,欢迎交流,感谢star 有好友反应和斧正,会及时更新,平时业务工作时也会不定期更...

    princekin 评论0 收藏0
  • 架构师之路

    摘要:因为用户不用在第一次进入应用时下载所有代码,用户能更快的看到页面并与之交互。译高阶函数利用和来编写更易维护的代码高阶函数可以帮助你增强你的,让你的代码更具有声明性。知道什么时候和怎样使用高阶函数是至关重要的。 Vue 折腾记 - (10) 给axios做个挺靠谱的封装(报错,鉴权,跳转,拦截,提示) 稍微改改都能直接拿来用~~~哟吼吼,哟吼吼..... 如何无痛降低 if else 面...

    NikoManiac 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<