1. 前言
1、本文主要分享一下vue2里面shared模块中几十个实用工具函数
2、记录一下本人的学习历程
2.源码地址
打包后的 vue.js 14行到379行,接下来就是解释其中的这些方法。
3. 工具函数
3.1 emptyObject
冻结对象让对象无法修改,也可以用来判默认空值
var emptyObject =Object.freeze({})
3.2 isUndef 判断是否未定义
function isUndef(v){
return v === undefined || v === null
}
3.3 isDef 判断是否定义
function isDef(v){
return v !== undefined || v !== null
}
3.4 isTrue 判断是否为true
function isTrue(v){
return v === true
}
3.5 isFalse 判断是否为false
function isFalse(v){
return v === false
}
3.6 isPrimitive 判断是否为原始值
function isPrimitive(value){
return (
typeof value === 'string' ||
typeof value === 'number' ||
typeof value === 'symbol' ||
typeof value === 'boolean'
)
}
3.7 isObject 判断是否为对象
function isObject(obj){
return obj !== null && typeof obj === 'object'
}
isObject([]) // true
// []与{}的typeof判断都为'object'
3.8 toRawType 获取值的原始类型字符串
// 提取toString方法,相当于object.toString()
var _toString = Object.prototype.toString;
// obj打印出来[object Object],截取后面的类型
// _toString.call(new Date) [object Date]
// _toString.call(new String) [object String]
function toRawType(value){
return _toString.call(value).slice(8,-1)
}
3.9 isPlainObject 严格的对象类型检查
function isPlainObject(obj){
return _toString.call(obj) === '[object Object]'
}
3.10 isRegExp 严格的RegExp类型检查
function isRegExp(v){
return _toString.call(v) === '[object RegExp]'
}
3.11 isValidArrayIndex 检查val是否为有效的数组索引
isFinite 是用来判断是否为一个有限数值
function isValidArrayIndex(val){
var n = parseFloat(String(val));
return n >= 0 && Math.floor(n) === n && isFinite(val)
}
3.12 isPromise 判断是否为promise
function isPromise(val){
return (
isDef(val) &&
typeof val.then === 'function' &&
typeof val.catch === 'function'
)
}
3.13 toString 将值转化为真实呈现的数据
function toString(val){
return val == null
? ''
: Array.isArray(val) || (isPlainObject(val) && val.toString === _toString)
? JSON.stringify(val,null,2)
: String(val)
}
拓展知识:JSON.stringify(value, replacer , space)
- value:将要序列化成 一个JSON 字符串的值。
- replacer(可选):如果该参数是一个函数,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换和处理;如果该参数是一个数组,则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中;如果该参数为null或者未提供,则对象所有的属性都会被序列化。
- space(可选):指定缩进用的空白字符串,用于美化输出(pretty-print);如果参数是个数字,它代表有多少的空格;上限为10。该值若小于1,则意味着没有空格;如果该参数为字符串(字符串的前十个字母),该字符串将被作为空格;如果该参数没有提供(或者为null)将没有空格。
3.14 toNumber 将值转化为数字,转化失败就保持原样
function toNumber(val){
var n = parseFloat(n);
return isNaN(n) ? val : n;
}
拓展:parseFloat() 函数解析字符串并返回浮点数
3.15 makeMap 生成map对象
function makeMap(str,expectsLowerCase){
var map = Object.create(null);
var list = str.split(',');
for(var i = 0;i < list.length; i++){
map[list[i]] = true;
}
return expectsLowerCase
? function(){ return map[val.toLowerCase()] }
: function(){ return map[val] }
}
3.16 isBuiltInTag 判断是否为内置tag
var isBuiltInTag = makeMap('slot,component', true)
3.17 isReservedAttribute 判断是否为内置属性
var isReservedAttribute = makeMap('key,ref,slot,slot-scope,is')
3.18 remove 删除数组的某项
function remove(arr, item){
if(arr.length){
var index = arr.indexOf(item);
if(index > -1){
return arr.splice(index,1)
}
}
}
3.19 hasOwn 检查对象是否具有属性
var hasOwnProperty = Object.prototype.hasOwnProperty;
var hasOwn = function(obj,key){
return hasOwnProperty.call(obj, key)
}
3.20 cached 缓存函数
function cached(fn){
var cache = Object.create(null);
return(function cachedFn(str){
var hit = cache[str];
return hit || (cache[str] = fn(str))
})
}
3.21 camelize 连字符转小驼峰
连字符 - 转驼峰 on-click => onClick
var camelizeRE = /-(\w)/g;
var camelize = cached(function(str){
return str.replace(camelizeRE, function(_,c){ return c ? c.toUpperCase() : ''; })
})
3.22 capitalize 首字母转大写
var capitalize = cached(function (str) {
return str.charAt(0).toUpperCase() + str.slice(1)
});
3.23 hyphenate 小驼峰转连字符
onClick => on-click
var hyphenateRE = /\B([A-Z])/g;
var hyphenate = cached(function (str) {
return str.replace(hyphenateRE, '-$1').toLowerCase()
});
3.24 polyfillBind bind 的垫片
function polyfillBind (fn, ctx) {
function boundFn (a) {
var l = arguments.length;
return l
? l > 1
? fn.apply(ctx, arguments)
: fn.call(ctx, a)
: fn.call(ctx)
}
boundFn._length = fn.length;
return boundFn
}
function nativeBind (fn, ctx) {
return fn.bind(ctx)
}
var bind = Function.prototype.bind
? nativeBind
: polyfillBind;
简单来说就是兼容了老版本浏览器不支持原生的 bind 函数。
3.25 toArray 把类数组转成真正的数组
function toArray(list, start){
start = start || 0;
var i = list.length - start;
var ret = new Array(i)
while(i--){
ret[i] = list[i + start]
}
return ret
}
3.26 extend 合并
function extend(to, _from){
for(var key in _from){
to[key] = _from[key]
}
return to
}
3.27 toObject 转对象
function toObject(arr) {
var res = {};
for(var i = 0; i< arr.length; i++){
if(arr[i]){
extend(res,arr[i])
}
}
return res
}
3.28 noop 空函数
function noop(a,b,c){}
3.29 no 一直返回 false
var no = function (a, b, c) { return false; };
3.30 identity 返回参数本身
var identity = function (_) { return _; };
3.31 genStaticKeys 生成静态属性
function genStaticKeys (modules) {
return modules.reduce(function (keys, m) {
return keys.concat(m.staticKeys || [])
}, []).join(',')
}
3.32 looseEqual 宽松相等
function looseEqual (a, b) {
if (a === b) { return true }
var isObjectA = isObject(a);
var isObjectB = isObject(b);
if (isObjectA && isObjectB) {
try {
var isArrayA = Array.isArray(a);
var isArrayB = Array.isArray(b);
if (isArrayA && isArrayB) {
return a.length === b.length && a.every(function (e, i) {
return looseEqual(e, b[i])
})
} else if (a instanceof Date && b instanceof Date) {
return a.getTime() === b.getTime()
} else if (!isArrayA && !isArrayB) {
var keysA = Object.keys(a);
var keysB = Object.keys(b);
return keysA.length === keysB.length && keysA.every(function (key) {
return looseEqual(a[key], b[key])
})
} else {
/* istanbul ignore next */
return false
}
} catch (e) {
/* istanbul ignore next */
return false
}
} else if (!isObjectA && !isObjectB) {
return String(a) === String(b)
} else {
return false
}
}
3.33 looseIndexOf 宽松版 indexOf
function looseIndexOf (arr, val) {
for (var i = 0; i < arr.length; i++) {
if (looseEqual(arr[i], val)) { return i }
}
return -1
}
3.34 once 确保函数只执行一次
利用闭包缓存方式判断只执行了一次
function once (fn) {
var called = false;
return function () {
if (!called) {
called = true;
fn.apply(this, arguments);
}
}
}
4. 总结
本文通过查看 Vue2 源码中 shared 模块代码,感觉也不难,但最好动手写写,多思考一下哪些场景用得上并且学习源码里面的思路。