前言
一个优秀的开发工程师,不应该重复的造轮子,而是应该在学习工作中,抽取和积累常用且经典的代码,保存为代码片段,有需要时随手翻出,节省重复码代码的时间来学习新知识,新业务,进行提高,这种工作坚持时间越长,效果越显著,良性的循环才会产生更大的惊喜,下面介绍一下一款代码片段的管理工具snippestlab。
我们日常JavaScript中的一些常用代码片段
1. makeMap
检测某值是否在字符串(逗号分隔的字符串)中存在, 运用了柯里化函数和缓存函数
/**
* Make a map and return a function for checking if a key
* is in that map.
* map 对象中的[name1,name2,name3,name4] 变成这样的map{name1:true,name2:true,name3:true,name4:true}
* 并且传进一个key值取值,这里用到策略者模式
* expectsLowerCase 是否开启小写转换
*/
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; //map 对象中的[name1,name2,name3,name4] 变成这样的map{name1:true,name2:true,name3:true,name4:true}
}
return expectsLowerCase
? function (val) {
return map[val.toLowerCase()];
} //返回一个柯里化函数 toLowerCase转换成小写
: function (val) {
return map[val];
}; //返回一个柯里化函数 并且把map中添加一个 属性建
}
不开启小写转换使用
var isBuiltInTag = makeMap("slot,component", true);
console.log(isBuiltInTag("SlOt")); // true 找不到的返回undefined
开启小写转换使用
var isBuiltInTag = makeMap("slot,component", false);
console.log(isBuiltInTag("SlOt")); // undefined
2. remove
删除数组中某一项, 该函数运用了indexOf,不可使用下标删除
/**
* Remove an item from an array
* //删除数组
*/
function remove(arr, item) {
if (arr.length) {
var index = arr.indexOf(item);
if (index > -1) {
return arr.splice(index, 1);
}
}
}
let arr = [{name:"张三"},{name:"李四"}];
let item = arr[1];
remove(arr, item) // 删除数组 arr 的第二项数据 | 返回值是删除的数据
3. hasOwn
检查是否为自身属性,会忽略原型链继承的属性
/**
* Check whether the object has the property.
* 检查对象属性是否是实例化还是原型上面的
* 该方法会忽略掉那些从原型链上继承到的属性,只有obj对象自身的属性才会返回true
*/
var hasOwnProperty = Object.prototype.hasOwnProperty;
function hasOwn(obj, key) {
return hasOwnProperty.call(obj, key);
}
let obj = {
name: "张三"
}
hasOwn(obj,'name') // true
hasOwn(obj,'__proto__') // false
4. cached
缓存函数,利用对象对字符串进行缓存
/**
* 缓存函数,利用对象对字符串进行缓存
* @param {*} fn
* @returns
*/
function cached(fn) {
var cache = Object.create(null);
return function cachedFn(str) {
var hit = cache[str];
return hit || (cache[str] = fn(str));
};
}
- 字符串转换成驼峰使用
/**
* 将连字符(-)分隔的字符串转换成驼峰写法
* 如: v-model 变成 vModel
*/
var camelizeRE = /-(\w)/g;
let camelize = cached(function (str) {
console.log(11);
return str.replace(camelizeRE, function (_, c) {
return c ? c.toUpperCase() : "";
});
});
console.log(camelize('user-name'));
console.log(camelize('user-name'));
输出
11 // 只会调用一次
userName
userName
- 首字母大写使用
**
* 将首字母大写
*/
var capitalize = cached(function (str) {
return str.charAt(0).toUpperCase() + str.slice(1);
});
console.log(capitalize('user')); // User
- 驼峰转连字符使用
// \B的用法: \B是非单词分界符,即可以查出是否包含某个字,如“ABCD”中是否包含“BCD”这个字。
var hyphenateRE = /\B([A-Z])/g;
var hyphenate = cached(function (str) {
//大写字母,加完减号又转成小写了 比如把驼峰 aBc 变成了 a-bc
//匹配大写字母并且两面不是空白的 替换成 '-' + '字母' 在全部转换成小写
return str.replace(hyphenateRE, "-$1").toLowerCase();
});
console.log(hyphenate('aBchFa')); // a-bch-fa
5. 改变this指向
/* istanbul ignore next */
//绑定事件 并且改变上下文指向
function polyfillBind(fn, ctx) {
function boundFn(a) {
var l = arguments.length;
// 1. 无参数直接调用 .call
// 2. 一个参数传参调用 .call
// 3. 其余参数 fn.apply(ctx, arguments)
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);
}
//bing 改变this上下文
var bind = Function.prototype.bind ? nativeBind : polyfillBind;
let o = {
a: 10,
fn: function() {
console.log(a);
}
}
a = 20;
console.log(bind(o.fn, o)()); // 不传参 a: 10
console.log(bind(o.fn, this)()); // 不传参 a: 20
let o = {
a: 10,
fn: function (a) {
console.log(a, this.a);
},
};
console.log(bind(o.fn, this)(30)); // 传参 a: 30 undefined(Node环境) | 20(Window)
console.log(bind(o.fn, this)(30)); // 传参 a: 30 10
6. 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;
}
function fn(a,b,c) {
let args = toArray(arguments, 1);
console.log(args); // [ 2, 3 ]
}
fn(1,2,3)
7. extend
对象合并,将from合并到to对象中
/**
* Mix properties into target object.
* * 浅拷贝
* 将属性混合到目标对象中。
* 类似 Object.assgin()
*/
//对象浅拷贝,参数(to, _from)循环_from的值,会覆盖掉to的值
function extend(to, _from) {
for (var key in _from) {
to[key] = _from[key];
}
return to;
}
- extend使用
let o = { name: "前端", obj:{ name: "张三" } };
let b = extend({}, o);
b.name ="掘金打咯"
b.obj.name = "加油"
console.log(o); // { name: '前端', obj: { name: '加油' } }
console.log(b); // { name: '掘金', obj: { name: '加油' } }
- toObject
// 将对象数组合并成一个对象
function toObject(arr) {
var res = {};
for (var i = 0; i < arr.length; i++) {
if(arr[i]) {
extend(res, arr[i]);
}
}
return res;
}
let arr = [ { name: "前端", obj:{ name: "张三" }, age: 19 }, { name: "手打", obj:{ name: "李四" } }]
console.log(toObject(arr)); // { name: '手打', obj: { name: '李四' }, age: 19 }
8. genStaticKeys
合并对象指定字符
/**
* Generate a static keys string from compiler modules.
*
* [{ staticKeys:1},{staticKeys:2},{staticKeys:3}]
* 连接数组对象中的 staticKeys key值,连接成一个字符串 str=‘1,2,3’
*/
function genStaticKeys(modules) {
return modules
.reduce(function (keys, m) {
//累加staticKeys的值变成数组
return keys.concat(m.staticKeys || []);
}, [])
.join(","); //转换成字符串
}
let staticKeys = [{ staticKeys: 1 }, { staticKeys: 2 }, { staticKeys: 3 }];
console.log(genStaticKeys(staticKeys)); // 1,2,3
9. once
函数只会执行一次
/**
* Ensure a function is called only once.
* 确保该函数只调用一次 闭包函数
*/
function once(fn) {
var called = false;
return function () {
if (!called) {
called = true;
return fn.apply(this, arguments);
}
};
}
add = (a, b) => {
console.log("执行");
return a + b;
};
let addOnce = once(add);
console.log(addOnce(1, 2));
console.log(addOnce(2,3));
执行 // add函数只会执行一次
3
undefined
配合 SnippestLab 的使用
软件详细介绍可以参考: sspai.com/post/30406