/* @flow */

/**
* Convert a value to a string that is actually rendered.
{ .. } [ .. ] 2 => ''
*/
export function _toString (val: any): string {
return val == null
? ''
: typeof val === 'object'
? JSON.stringify(val, null, 2) //2 是控制字符串系列化后的空格为2
: String(val)
} /**
* Convert a input value to a number for persistence.
* If the conversion fails, return original string.
刻意把 输入框的值转换成数字, 如失败, 则还原
如 '123abc' 会转换成 123
这里没有用parseInt 是因为parseInt对浮点型转换不准确, 如
 
  parseInt(0.0000008,10) => 8 parseFloat(0.0000008,10) => 8e-7
  而且对于字符串, parFloat只能按十进制来转换, parseInt('0200',8) => 128; parseFloat('0200',8) => 200
*/
export function toNumber (val: string): number | string {
const n =parseFloat(val)return isNaN(n) ? val : n
} /**
* Make a map and return a function for checking if a key
* is in that map.
输入标签 'div,slot,span'等, div或者slot作为一个对象的key, 返回一个函数
检查传入的key是否在map中

*/
export function makeMap (
str: string,
expectsLowerCase?: boolean //传入的key还可以不区分大小写
): (key: string) => true | void {
const map = Object.create(null) //这里没有使用 new Object 或者 = {}; 是为了创建没有 __proto__属性的 真空对象
const list: Array<string> = str.split(',') //这里用到了闭包, 把map 缓存了起来 for (let i = 0; i < list.length; i++) {
map[list[i]] = true
}
return expectsLowerCase
? val => map[val.toLowerCase()]
: val => map[val]
} /**
* Check if a tag is a built-in tag.
检查一个标签是否是 内置标签
*/
export const isBuiltInTag = makeMap('slot,component', true) /**
* Remove an item from an array
利用indexOf splice 移除一个值
*/
export function remove (arr: Array<any>, item: any): Array<any> | void {
if (arr.length) {
const index = arr.indexOf(item)
if (index > -1) {
return arr.splice(index, 1)
}
}
} /**
* Check whether the object has the property.
缓存原型方法, 避免每次去对象的原型找这个hasOwnProperty方法, 减少一丁点性能损耗
*/
const hasOwnProperty = Object.prototype.hasOwnProperty

export function hasOwn (obj: Object, key: string): boolean {
return hasOwnProperty.call(obj, key)
} /**
* Check if value is primitive
只有 字符串 数字 才是原始类型
*/
export function isPrimitive (value: any): boolean {
return typeof value === 'string' || typeof value === 'number'
} /**
* Create a cached version of a pure function.
利用闭包缓存一个函数执行特定参数的结果, 比如
执行 var cFn1 = cached( fn1 ); cFn1(2); 第二次调用 cFn1(2)的时候, 就可以利用第一次的结果,
适合会多次调用一个函数, 而且参数有可能重复的情况
由于是利用了缓存, 所以传入的函数应该是纯函数, 就是每次如果参数一样, 结果必须一样, 不能是random这样的函数
*/
export function cached<F: Function> (fn: F): F {
const cache = Object.create(null)
return (function cachedFn (str: string) {
const hit = cache[str]
return hit || (cache[str] = fn(str))
}: any)
} /**
* Camelize a hyphen-delimited string.
把 'ms-box-shadow' 这样的用-分割的连字符, 驼峰化 => msBoxShadow ; 有利于在js中设置样式
*/
const camelizeRE = /-(\w)/g
export const camelize = cached((str: string): string => {
//c 就是(\w)这个子项, 前面需要一个-; 所以 -box 会变成 -Box
return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
}) /**
* Capitalize a string.
abc 变成 Abc
*/
export const capitalize = cached((str: string): string => {
return str.charAt(0).toUpperCase() + str.slice(1)
}) /**
* Hyphenate a camelCase string.
驼峰转成链接字符 abcAb => abc-ab
*/
const hyphenateRE = /([^-])([A-Z])/g
export const hyphenate = cached((str: string): string => {
return str
.replace(hyphenateRE, '$1-$2') //转两次?
.replace(hyphenateRE, '$1-$2')
.toLowerCase()
}) /**
* Simple bind, faster than native
自定义的bind方法, 比原生快那么一点, 原理?
*/
export function bind (fn: Function, ctx: Object): Function {
function boundFn (a) {
const l: number = arguments.length
return l
? l > 1
? fn.apply(ctx, arguments)
: fn.call(ctx, a)
: fn.call(ctx)
}
// record original fn length
boundFn._length = fn.length
return boundFn
} /**
* Convert an Array-like object to a real Array.
数组转换类数组, 这里没有用[].slice.call?
*/
export function toArray (list: any, start?: number): Array<any> {
start = start || 0
let i = list.length - start
const ret: Array<any> = new Array(i)
//这里没使用push while (i--) {
ret[i] = list[i + start]
}
return ret
} /**
* Mix properties into target object.
太简单的混入
*/
export function extend (to: Object, _from: ?Object): Object {
for (const key in _from) {
to[key] = _from[key]
}
return to
} /**
* Quick object check - this is primarily used to tell
* Objects from primitive values when we know the value
* is a JSON-compliant type.
简单判断一个对象
*/
export function isObject (obj: mixed): boolean {
return obj !== null && typeof obj === 'object'
} /**
* Strict object type check. Only returns true
* for plain JavaScript objects.
确保是一个完全的对象, 而不是数组 null RegExp 之类的东西
*/
const toString = Object.prototype.toString
const OBJECT_STRING = '[object Object]'
export function isPlainObject (obj: any): boolean {
return toString.call(obj) === OBJECT_STRING
} /**
* Merge an Array of Objects into a single Object.
['a','b'] => {0:'a',1:'b'}
*/
export function toObject (arr: Array<any>): Object {
const res = {}
for (let i = 0; i < arr.length; i++) {
if (arr[i]) {
extend(res, arr[i])
}
}
return res
} /**
* Perform no operation. 一个空函数
*/
export function noop () {} /**
* Always return false. 减少书写?
*/
export const no = () => false /**
* Return same value 需要利用函数来返回相同值?
*/
export const identity = (_: any) => _ /**
* Generate a static keys string from compiler modules.
把modules的每个statickeys 链接起来 形成一个特定的静态key
*/
export function genStaticKeys (modules: Array<ModuleOptions>): string {
return modules.reduce((keys, m) => {
return keys.concat(m.staticKeys || [])
}, []).join(',')
} /**
* Check if two values are loosely equal - that is,
* if they are plain objects, do they have the same shape?
判断两个对象 的值是否 相等, 而不用考虑对象地址是否相同
var a = {}; var b = {}; looseEqual(a,b) => true, 对于 null 和 0 false是不相等的
*/
export function looseEqual (a: mixed, b: mixed): boolean {
const isObjectA = isObject(a)
const isObjectB = isObject(b)
if (isObjectA && isObjectB) {
try {
return JSON.stringify(a) === JSON.stringify(b)
} catch (e) {
// possible circular reference
return a === b
}
} else if (!isObjectA && !isObjectB) {
return String(a) === String(b)
} else {
return false
}
}

//比如 arr是 [{"a":1},...] looseIndexOf( arr, {"a":1} ) => 0
export function looseIndexOf (arr: Array<mixed>, val: mixed): number {
for (let i = 0; i < arr.length; i++) {
if (looseEqual(arr[i], val)) return i
}
return -1
} /**
* Ensure a function is called only once. 保证这个函数只调用一次 var f = once(fn1); f(); f()没执行fn1
*/
export function once (fn: Function): Function {
let called = false
return () => {
if (!called) {
called = true
fn()
}
}
}

vue.js 源代码学习笔记 ----- 工具方法 share的更多相关文章

  1. vue.js 源代码学习笔记 ----- 工具方法 env

    /* @flow */ /* globals MutationObserver */ import { noop } from 'shared/util' // can we use __proto_ ...

  2. vue.js 源代码学习笔记 ----- 工具方法 option

    /* @flow */ import Vue from '../instance/index' import config from '../config' import { warn } from ...

  3. vue.js 源代码学习笔记 ----- 工具方法 lang

    /* @flow */ // Object.freeze 使得这个对象不能增加属性, 修改属性, 这样就保证了这个对象在任何时候都是空的 export const emptyObject = Obje ...

  4. vue.js 源代码学习笔记 ----- 工具方法 perf

    import { inBrowser } from './env' export let mark export let measure if (process.env.NODE_ENV !== 'p ...

  5. vue.js 源代码学习笔记 ----- 工具方法 error

    import config from '../config' import { warn } from './debug' import { inBrowser } from './env' // 这 ...

  6. vue.js 源代码学习笔记 ----- 工具方法 debug

    import config from '../config' import { noop } from 'shared/util' let warn = noop let tip = noop let ...

  7. vue.js 源代码学习笔记 ----- 工具方法 props

    /* @flow */ import { hasOwn, isObject, isPlainObject, capitalize, hyphenate } from 'shared/util' imp ...

  8. vue.js 源代码学习笔记 ----- html-parse.js

    /** * Not type-checking this file because it's mostly vendor code. */ /*! * HTML Parser By John Resi ...

  9. vue.js 源代码学习笔记 ----- instance render

    /* @flow */ import { warn, nextTick, toNumber, _toString, looseEqual, emptyObject, handleError, loos ...

随机推荐

  1. 让boost.variant支持lambda表达式访问

    前言 之前写个过一篇博客叫<浅谈boost.variant的几种访问方式>,里面讲到了可以通过访问者方式来获取variant的值,但是在重载函数operator()里面只能够获取varia ...

  2. Python3.x:logging模块对运行过程记录

    Python3.x:logging模块对运行过程记录 示例: import logging # 设置 logger = logging.getLogger() #set loghandler #默认路 ...

  3. 用python收集系统信息

    实现的功能 搜集系统消息,有生产商,CPU型号,核数,内存,主机名,发行版名称 可运行的系统 目前已在RHEL, Ubuntu, Archlinux上测试通过 获取不同发行版主机名逻辑判断思路分析 大 ...

  4. Spring Boot 上传图片文件

    步骤一:基于前面springboot入门小demo 基于的springboot入门小demo,已包含了前面文章的知识点(比如:热部署.全局异常处理器). 步骤二:创建uploadPage.jsp上传页 ...

  5. Windows下安装Redis服务、搭建简单Redis主从复制

    Redis拥有非常强大的主从复制功能,而且还支持一个master可以拥有多个slave,而一个slave又可以拥有多个slave,从而形成强大的多级服务器集群架构.目前在同一台window下安装三个r ...

  6. Win10 initluictrl failed问题

    问题描述 启动win10之后,所有的软件.快捷方式无法访问,双击之后没有响应但联网正常. 解决方法 win键+S弹出选项框,选择cmd(管理员). 键入命令:netsh winsock reset c ...

  7. java 连接 redis集群时报错:Could not get a resource from the pool

    由于弄这个的时候浪费了太多的时间,所以才记录下这个错,给大伙参考下 检查了一下,配置啥的都没问题的,但在redis集群机器上就可以,错误如下: Exception in thread "ma ...

  8. 创建Jmeter中使用的jar包中的工具类方法

    1. 在IDEA中新建一个maven工程. 2. 编写工具类方法,如加密算法.此处以加法为例. package DemoTest; public class DemoClass{ public int ...

  9. Kubernetes容器运行时(CRI)简介

    Kubernetes节点的底层由一个叫做“容器运行时”的软件进行支撑,它负责比如启停容器这样的事情.最广为人知的容器运行时当属Docker,但它不是唯一的.事实上,容器运行时这个领域发展迅速.为了使K ...

  10. 【Python】模块学习之使用paramiko连接Linux,远程执行命令,上传下载、文件

    本文主要介绍paramiko远程执行linux命令,及在服务器上进行文件的上传.下载 paramiko是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接. ...