(1)_toString
function _toString (val) {
return val == null
? ''
: typeof val === 'object'
? JSON.stringify(val, null, 2)
: String(val)
}
这个函数还是比较好理解的,如果传入的值为空,则返回空字符串;否则,如果传入的是对象,则将其变为 JSON 的数据格式(强调:JSON 是字符串!);否则以字符串的形式输出。
这里面,我们需要学习的是 JSON.stringify(val, null, 2) 这个方法,其中的 2 表示缩进为 2 个空格,其中的第二个 null 参数表示序列化,如果为 null 则表示所有属性都被序列化。
(2) toNumber
function toNumber (val) {
var n = parseFloat(val);
return isNaN(n) ? val : n
}
该函数表示将传入的值转化为数值,如果传入的不是数字,则返回这个值。这里面,我们需要了解到 parseFloat 这个函数,返回它遇到的第一个不是数字的前面的所有数字。
比如说:parseFloat('123ab'),返回的是 123;parseFloat('ab123') 则返回 NaN 。
所以,这也是为什么这里使用了 isNaN() 这个函数。当然,在 ES6 的规范中,建议还是使用 Number.isNaN() 和 Number.parseFloat() 更好。
(3)makeMap
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 (val) { return map[val.toLowerCase()]; }
: function (val) { return map[val]; }
}
// 检查 tag 标签是否为内置的标签
var isBuiltInTag = makeMap('slot,component', true);
关于这个函数,官方的说法是:创建一个 map 并返回一个函数以确定是否该键存在于这个 map 中。至少目前,我们看不出它的作用来,后面用到了再说吧。
其中我们需要学习到 Object.create() 这个方法是干什么的,它和 new Object() 有什么区别。Object.create() 这个方法的用处就是创建一个对象,它可以继承指定的原型。比如说,我有一个对象:
Object.create(null, {
a: {
value: 1
}
}
它等价于:
const obj = {
a: 1
}
记住,这是错误的!因为我们这里设置的第一个参数为 null,那么这个对象是没有原型的!也就是说,它没有对象原型上的方法。如果要等价的话,那么我们的参数要设置为 {}。
Object.create({}, {
a: {
value: 1
}
}
这样,才是等价的。
在这里,设置为 null 的意思就是说,创建一个没有原型的对象。
(4)remove$1
function remove$1 (arr, item) {
if (arr.length) {
var index = arr.indexOf(item);
if (index > -1) {
return arr.splice(index, 1)
}
}
}
这个函数的意思是,从数组中移除掉一个值。这个函数很典型。首先,如果它是一个数组,那么则找到想要的这个值第一次出现时的索引值;如果数组中存在这个值,那么就使用 splice() 这个方法将其移除并返回。
我们来测试一下这个方法:
remove$1([1, 2, 3], 2)
// 返回 [2],原数组变为[1, 3]
remove$1([1, 2, 3, 2], 2)
// 返回 [2],原数组变为[1, 3, 2]
这个函数我们平时也是可以用到的,但是这个函数呢,只能返回第一个被查询到的值。这是 indexOf() 这个函数的局限性,记住这一点。
(5)hasOwnProperty
var hasOwnProperty = Object.prototype.hasOwnProperty;
function hasOwn (obj, key) {
return hasOwnProperty.call(obj, key)
}
这个函数的作用是检查该属性是否是这个对象所拥有的。说的更加直白一点就是,对象是否有这个键(key),我们来测试一下:
const obj = {
a: 1,
b: 2
};
console.log(hasOwn(obj, 'c')); // false
console.log(hasOwn(obj, 'a')); // true
这个 obj 中是没有 c 这个键的。这个是被封装起来的函数,平时如果单独使用的话,则可以直接调用 Object.prototype.hasOwnProperty() 这个方法的。
(6)isPrimitive
function isPrimitive (value) {
return typeof value === 'string' || typeof value === 'number'
}
该函数是判断该值是否为原始值。
原始值有六种类型,分别为 String、Number、Boolean、Symbol、Null 和 Undefined。
当然这里只判断了该值是字符串还是数值类型。
(7)cached
function cached (fn) {
var cache = Object.create(null);
return (function cachedFn (str) {
var hit = cache[str];
return hit || (cache[str] = fn(str))
})
}
这个方法的作用是创建一个纯函数的缓存版本。单独看,肯定是看不懂这个函数想表达一个什么意思。来,我们接着往下看:
(1)驼峰化以连字符分隔的字符串。
var camelizeRE = /-(\w)/g;
var camelize = cached(function (str) {
return str.replace(camelizeRE, function (_, c) { return c ? c.toUpperCase() : ''; })
});
(2)大写字符串。
var capitalize = cached(function (str) {
return str.charAt(0).toUpperCase() + str.slice(1)
});
(3)连接驼峰命名的字符串。
var hyphenateRE = /([^-])([A-Z])/g;
var hyphenate = cached(function (str) {
return str
.replace(hyphenateRE, '$1-$2')
.replace(hyphenateRE, '$1-$2')
.toLowerCase()
});
我们先不看上面三个代码,我们先来试着理解 cache() 这个函数。这个函数是干什么的?在 JavaScript 中,有一个很经典的函数写法叫做 “缓存策略”,它是用来加速我们的数据的读取速度的。
它的实现原理:创建一个对象,将我们所写的东西保存到这个对象中,如果说我们后面再次用到了这个东西,那么 JavaScript 就不需要再计算一遍了,直接将这个对象中我们需要的东西提取出来就好了。
这是提高执行速度的一种十分有效的办法,可以作为了解,很多的库都会用到它。
(8)bind$1
function bind$1 (fn, ctx) {
function boundFn (a) {
var l = arguments.length;
return l
? l > 1
? fn.apply(ctx, arguments)
: fn.call(ctx, a)
: fn.call(ctx)
}
// 记录原始的 fn 长度
boundFn._length = fn.length;
return boundFn
}
该函数的作用与原生的 bind() 方法一致,但官方说,这个函数比原生要快。其中的 ctx 参数的意思是 context,即上下文。其实也就是我们常使用的 this 指定的上下文环境。
(9)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
}
该方法将一个类数组对象转换成真正的数组对象。其中的 list 表示类数组对象,而 start 表示起始的索引值。当然,我们的 ES6 中的 Array.from() 也可以转换,可是它不能指定起始的位置。
我们来测试一下:
console.log(toArray({
0: 'a',
1: 'b',
2: 'c',
length: 3
}, 1));
// ["b", "c"]
当然了,其实我们使用 ES6 同样可以达到这个效果。我来写一个能达到同样效果的函数吧:
function toArray(list, start = 0) {
const realArray = Array.from(list);
return realArray.slice(start);
}
不仅如此,我还可以设置结束的位置:
function toArray(list, start = 0, end = list.length) {
const realArray = Array.from(list);
return realArray.slice(start, end);
}
好了,这个函数就到此结束啦。
(10)extend
function extend (to, _from) {
for (var key in _from) {
to[key] = _from[key];
}
return to
}
该函数的作用是:将属性混合到目标对象中。说的直白一点就是拷贝对象的属性。
比如我这里有一个空对象,还有另一个对象,将另一个对象中的属性拷贝到这个空对象中去:
const a = {};
const b = {
a: 1,
b: 2
};
extend(a, b);
console.log(a); // {a: 1, b: 2}