本文参加了由公众号@若川视野发起的每周源码共读活动,点击了解详情一起参与。 这是源码共读的第 24 期,链接:juejin.cn/post/707976…
前言
参与源码共读,让我们成为更好的自己~
1.工具函数
项目地址,文件路径:vue/src/shared/util
1.1 冻结对象
freezeObject = Object.freeze({});
1.2 是否未定义
function isUndef(value) {
return value === 'undefined || value === null;
}
1.3 是否已定义
function isDef(value) {
return value !== undefined && value !== null;
}
1.4 是否为true
function isTrue(value) {
return value === true;
}
1.5 是否为false
function isFalse(value) {
return value === false;
}
1.6 是否为原始值(number,string,symbol,boolean)
function isPrimitive(value) {
return (
typeof value === 'string' ||
typeof value === 'number' ||
typeof value === 'boolean' ||
typeof value === 'symbol'
)
}
1.7 是否为Object
function isObject(value) {
return value !== null && typeof value === 'object';
}
1.8 是否为false
function isFalse(value) {
return value === false;
}
1.9 转原始类型
_toString = Object.prototype.toString;
function toRawType(value) {
return _toString.call(value).slice(8, -1);
}
1.10 是否为纯对象
function isPlainObject(value) {
return _toString.call(value) === '[object object]';
}
1.11 是否为正则表达式
function isRegExp(value) {
return _toString.call(value) === '[object, RegExp]';
}
1.12 是否为可用数组索引值
function isValidArrayIndex(value) {
const n = parseFloat(value);
return n >= 0 && Math.floor(n) === n && isFinite(value);
}
parseFloat()方法返回一个浮点数。mdn
isFinite()方法判断是否为有限数值。mdn
1.13 是否是Promise
function isPromise(value) {
return isDef(value) &&
typeof value.then === 'function' &&
typeof value.catch === 'function'
}
1.14 toString转字符串
function toString(value) {
return value == null ?
'' :
Array.isArray(value) || isPlainObject(value) || value.toString === _toString ?
JSON.stringify(value, null, 2) :
String(value);
}
JSON.stringify(value, [replacer], [space]) mdn
1.15 toNumber转数字
function toNumber(value) {
const num = parseFloat(value);
return isNaN(num) ? value : num;
}
parseFloat: 函数解析一个参数(必要时先转换为字符串)并返回一个浮点数。
1.16 makeMap生成一个Map
function makeMap(str, expectsLowerCase) {
const map = Object.create(null);
const list = str.split(',');
for(let i = 0; i < list.length; i++) {
map[list[i]] = true;
}
return expects ? val => map[val.toLowCase()] : val => map[val];
}
传入一个用 , 分隔的字符串生成一个map,返回一个函数查看key是否存在于map中。
1.17 remove
移除数组中的一项
function remove(array, item) {
const len = array.length;
if(len) {
if(item === array[len - 1]) {
array.length = len - 1;
return;
}
}
const index = array.indexOf(item);
if(index > -1) {
return array.slice(index, 1);
}
}
1.18 hasOwn
检查是否是自己的属性
const hasOwnProperty = Object.prototype.hasOwnProperty
function hasOwn(obj, key) {
return hasOwnProperty.call(obj, key);
}
1.19 cached
检查是否是自己的属性
function cached(fn) {
const cache = Object.create(null);
return function(s) {
const h = cache[s];
return h || (cache[s] = fn(s));
}
}
1.20 camelizeRe
连字符转小驼峰
const camelizeRe = /-(\w)/g;
const camelize = cached((str) => {
return str.replace(camelizeRe, (_, s) => s ? s.toUpperCase() : '')
})
1.21 capitalize
首字母转大写
const capitalize = cached((str) => {
return str.charAt(0).toUpperCase() + str.slice(1);
})
1.22 hyphenate
连字符转小驼峰
const hyphenateRE = /\B(A-Z)/g;
const hyphenate = cached((str) => {
return str.replace(hyphenateRE, '-$1').toLowerCase();
})
1.23 polyfillBind
function polyfillBind(fn, ctx) {
function boundFn(v) {
const len = arguments.length;
return len ?
len > 1 ?
fn.apply(ctx, arguments) :
fn.call(ctx, v) :
fn.call(ctx);
}
boundFn._length = fn.length;
return boundFn;
}
const nativeBind(fn, ctx) {
return fn.bind(ctx);
}
const bind = Function.prototype.bind ? nativeBind : polyfillBind;
1.24 toArray
function toArray(list, start = 0) {
let i = list.length - start;
const result = new Array(i);
while(--i) {
result[i] = list[i + start];
}
return result;
}
1.25 extend
合并对象
function extend(to, from) {
for(const i in from) {
to[i] = from[i];
}
return to;
}
1.26 toObject
function toObject(arr) {
const obj = {};
for(let j = 0; j < arr.length; j++) {
if(arr[j]) {
extends(obj, arr[j]);
}
}
return obj;
}
1.27 noop
function noop(a, b, c) { };
1.28 no
const no = (a, b, c) => false;
1.29 identity
const identity = (a) => return a;
1.30 genStaticKeys
function genStaticKeys(arr) {
return arr
.reduce((pre, cur) => pre.concat(cur.staticKeys), [])
.join(',');
};
1.31 looseEqual
宽松相等
function looseEqual(a, b) {
if(a === b) {
return true;
}
const isObjectA = isObject(a);
const isObjectB = isObject(b);
if(isObjectA && isObjectB) {
try {
const isArrayA = isArray(a);
const isArrayB = isArray(b);
if(isArrayA && isArrayB) {
return (
a.length === b.length &&
a.every((ele, ids) => looseEqual(ele, b[ids]));
)
} else if(a instanceof Date && b instanceof Date) {
return a.getTime() === b.getTime();
} else if(!isArrayA && !isArrayB) {
const keyA = Object.keys(a);
const keyB = Object.keys(b);
return (
keyA.length === keyB.length &&
keyA.every((ele) => looseEqual(a[ele], b[ele]));
)
} else {
return false;
}
} catcth(e) {
return false;
}
} else if(!isObjectA && !isObjectB) {
return String(a) === String(b);
} else {
return false;
}
};
1.32 looseIndexOf
原生indexOf匹配为严格相等
function looseIndexOf(arr, value) {
for(let j = 0; j < arr.length; j++) {
if(looseEqual(arr[j], value)) {
return j;
}
}
return -1;
}
1.33 once
利用闭包使函数只能调用一次
function once(fn) {
let called = false;
return function() {
if(!called) {
called = true;
fn.apply(this, arguments);
}
}
}
总结
这期源码大部分都能理解看懂,但是部分工具函数在工作中没有实际运用过,就当巩固基础查缺补漏啦,继续加油~