util.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /* @flow */
  2. /**
  3. * Convert a value to a string that is actually rendered.
  4. */
  5. export function _toString (val: any): string {
  6. return val == null
  7. ? ''
  8. : typeof val === 'object'
  9. ? JSON.stringify(val, null, 2)
  10. : String(val)
  11. }
  12. /**
  13. * Convert a input value to a number for persistence.
  14. * If the conversion fails, return original string.
  15. */
  16. export function toNumber (val: string): number | string {
  17. const n = parseFloat(val, 10)
  18. return (n || n === 0) ? n : val
  19. }
  20. /**
  21. * Make a map and return a function for checking if a key
  22. * is in that map.
  23. */
  24. export function makeMap (
  25. str: string,
  26. expectsLowerCase?: boolean
  27. ): (key: string) => true | void {
  28. const map = Object.create(null)
  29. const list: Array<string> = str.split(',')
  30. for (let i = 0; i < list.length; i++) {
  31. map[list[i]] = true
  32. }
  33. return expectsLowerCase
  34. ? val => map[val.toLowerCase()]
  35. : val => map[val]
  36. }
  37. /**
  38. * Check if a tag is a built-in tag.
  39. */
  40. export const isBuiltInTag = makeMap('slot,component', true)
  41. /**
  42. * Remove an item from an array
  43. */
  44. export function remove (arr: Array<any>, item: any): Array<any> | void {
  45. if (arr.length) {
  46. const index = arr.indexOf(item)
  47. if (index > -1) {
  48. return arr.splice(index, 1)
  49. }
  50. }
  51. }
  52. /**
  53. * Check whether the object has the property.
  54. */
  55. const hasOwnProperty = Object.prototype.hasOwnProperty
  56. export function hasOwn (obj: Object, key: string): boolean {
  57. return hasOwnProperty.call(obj, key)
  58. }
  59. /**
  60. * Check if value is primitive
  61. */
  62. export function isPrimitive (value: any): boolean {
  63. return typeof value === 'string' || typeof value === 'number'
  64. }
  65. /**
  66. * Create a cached version of a pure function.
  67. */
  68. export function cached (fn: Function): Function {
  69. const cache = Object.create(null)
  70. return function cachedFn (str: string): any {
  71. const hit = cache[str]
  72. return hit || (cache[str] = fn(str))
  73. }
  74. }
  75. /**
  76. * Camelize a hyphen-delmited string.
  77. */
  78. const camelizeRE = /-(\w)/g
  79. export const camelize = cached((str: string): string => {
  80. return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
  81. })
  82. /**
  83. * Capitalize a string.
  84. */
  85. export const capitalize = cached((str: string): string => {
  86. return str.charAt(0).toUpperCase() + str.slice(1)
  87. })
  88. /**
  89. * Hyphenate a camelCase string.
  90. */
  91. const hyphenateRE = /([^-])([A-Z])/g
  92. export const hyphenate = cached((str: string): string => {
  93. return str
  94. .replace(hyphenateRE, '$1-$2')
  95. .replace(hyphenateRE, '$1-$2')
  96. .toLowerCase()
  97. })
  98. /**
  99. * Simple bind, faster than native
  100. */
  101. export function bind (fn: Function, ctx: Object): Function {
  102. function boundFn (a) {
  103. const l: number = arguments.length
  104. return l
  105. ? l > 1
  106. ? fn.apply(ctx, arguments)
  107. : fn.call(ctx, a)
  108. : fn.call(ctx)
  109. }
  110. // record original fn length
  111. boundFn._length = fn.length
  112. return boundFn
  113. }
  114. /**
  115. * Convert an Array-like object to a real Array.
  116. */
  117. export function toArray (list: any, start?: number): Array<any> {
  118. start = start || 0
  119. let i = list.length - start
  120. const ret: Array<any> = new Array(i)
  121. while (i--) {
  122. ret[i] = list[i + start]
  123. }
  124. return ret
  125. }
  126. /**
  127. * Mix properties into target object.
  128. */
  129. export function extend (to: Object, _from: ?Object): Object {
  130. for (const key in _from) {
  131. to[key] = _from[key]
  132. }
  133. return to
  134. }
  135. /**
  136. * Quick object check - this is primarily used to tell
  137. * Objects from primitive values when we know the value
  138. * is a JSON-compliant type.
  139. */
  140. export function isObject (obj: mixed): boolean {
  141. return obj !== null && typeof obj === 'object'
  142. }
  143. /**
  144. * Strict object type check. Only returns true
  145. * for plain JavaScript objects.
  146. */
  147. const toString = Object.prototype.toString
  148. const OBJECT_STRING = '[object Object]'
  149. export function isPlainObject (obj: any): boolean {
  150. return toString.call(obj) === OBJECT_STRING
  151. }
  152. /**
  153. * Merge an Array of Objects into a single Object.
  154. */
  155. export function toObject (arr: Array<any>): Object {
  156. const res = {}
  157. for (let i = 0; i < arr.length; i++) {
  158. if (arr[i]) {
  159. extend(res, arr[i])
  160. }
  161. }
  162. return res
  163. }
  164. /**
  165. * Perform no operation.
  166. */
  167. export function noop () {}
  168. /**
  169. * Always return false.
  170. */
  171. export const no = () => false
  172. /**
  173. * Generate a static keys string from compiler modules.
  174. */
  175. export function genStaticKeys (modules: Array<ModuleOptions>): string {
  176. return modules.reduce((keys, m) => {
  177. return keys.concat(m.staticKeys || [])
  178. }, []).join(',')
  179. }
  180. /**
  181. * Check if two values are loosely equal - that is,
  182. * if they are plain objects, do they have the same shape?
  183. */
  184. export function looseEqual (a: mixed, b: mixed): boolean {
  185. /* eslint-disable eqeqeq */
  186. return a == b || (
  187. isObject(a) && isObject(b)
  188. ? JSON.stringify(a) === JSON.stringify(b)
  189. : false
  190. )
  191. /* eslint-enable eqeqeq */
  192. }
  193. export function looseIndexOf (arr: Array<mixed>, val: mixed): number {
  194. for (let i = 0; i < arr.length; i++) {
  195. if (looseEqual(arr[i], val)) return i
  196. }
  197. return -1
  198. }