1 debounce
function debounce(fun, wait = 2000) {
let timer = 0;
return function(...args) {
if (timer) clearTimeout(timer);
timer = setTimeout(() => { fun.aplly(this, args) }, wait)
}
}
2 throttle
function throttle(fun, wait= 2000){
let lastTime = 0;
return function (...args) {
let now = + new Date();
if (now - lastTime > wait){
fun.apply(this, args);
lastTime = now;
}
}
}
3 deepclone
3.1 json
- 无法实现对函数 、RegExp等特殊对象的克隆
- 会抛弃对象的constructor,所有的构造函数会指向Object
- 对象有循环引用,会报错
const newObj = JSON.parse(JSON.stringify(oldObje));
3.2 递归
function deepClone(obj) {
let res = obj;
if(typeof(obj) !== 'object') return res;
res = Array.isArray(obj) ? [] : {};
for(let i in obj) {
res[i] = typeof(obj[i]) === 'object' ? deepClone(obj[i]) : obj[i];
}
return res;
}
4 Event(event bus)
event bus既是node中各个模块的基石,又是前端组件通信的依赖手段之一,同时涉及了订阅-发布设计模式,是非常重要的基础
class EventEmitter {
constructor() {
this._events = this._event || new Map(); //存储事件
this._maxListeners = this._maxListeners || 10; //监听上限
}
//触发监听名为type的事件
emit(type, ...args) {
let events = this._events.get(type);
if (!events) return;
for (let i = 0; i < events.length; i++) {
events[i].apply(this, args);
};
}
//添加监听名为type的事件fun
addListener(type, fun) {
let events = this._events.get(type);
if (events) {
events.push(fn);
} else {
this._events.set(type, [fun]);
};
}
//移除监听名为type的事件fun
removeListener(type, fun) {
let events = this._events.get(type);
if (!event) return;
for (let i = 0; i < events.length; i++) {
if (events[i] === fn) {
events.splice(i, 1);
if (events.length === 0) events = null;
};
};
}
}
5 new function
Object.create(proto, [propertiesObject])
//方法创建一个新对象,使用现有的对象来提供新创建的对象的proto。
//模拟 new 操作符
function myNew(fn, ...args) {
//1、创建一个空对象并把空对象 __proto__ 指向构造函数的 prototype
let instance = Object.create(fn.prototype);
//2、执行构造函数
let res = fn.apply(instance, args);
//3、返回值为object类型则作为new方法的返回值返回,否则返回上述全新对象
return typeof res === 'object' ? res: instance;
}
6 promise
function myPromise(fun) {
this.status = 'pending';
this.value = undefined;
this.reason = undefined;
//私有方法
let resolve = (value) => {
if (this.status === 'pending') {
this.value = value;
this.status = 'resolved'
}
};
let reject = (reason) => {
if (this.status === 'pending') {
this.reason = reason;
this.status = 'rejected';
}
}
//添加 then 方法
this.then = function(onFullfilled, onRejected) {
switch(this.status) {
case 'resolved':
onFullfilled(this.value);
break;
case 'rejected':
onRejected(this.reason);
break;
default:
}
}
try {
fun(resolve, reject);
} catch(e) {
reject(e);
}
}
7 模版渲染
function render(template, data) {
const reg = /\{\{(\w+)\}\}/;
while (reg.test(template)) {
const name = reg.exec(template)[1];
if (ata[name]) template = template.replace(reg, data[name])
}
return template;
}
//测试
let template = '我是{{name}},年龄{{age}},性别{{sex}}';
let data = {
name: '姓名',
age: 18
}
render(template, data);
8 转驼峰命名
let str = 'get-element-by-id';
function toCamel(str) {
return str.replace(/-\w/g, (item) => item.slice(1).toUpperCase());
}
9 字符串
9.1 最多字符
let str = "abcabcabcbbccccc";
let num = 0;
let char = '';
str = str.split('').sort().join('');
let re = /(\w)\1+/g;
str.replace(re,($0,$1) => {
if(num < $0.length){
num = $0.length;
char = $1;
}
});
console.log(`字符最多的是${char},出现了${num}次`);
9.2 千分位分隔符
function parseToMoney(num) {
let [integer, decimal] = num.toFixed(2).split('.');
integer = integer.replace(/\d(?=(\d{3})+$)/g, '$&,');
return integer + '.' + decimal;
}
10 flat
10.1 Array.prototype.flat()
flat( )用于将嵌套的数组“拉平”,变成一维数组。该方法返回一个新数组,对原数据没有影响。
参数表示展开层数,infinity 不管多少层都会展开
let res = [1, 2, [3, [4]]].flat(infinity); //[1, 2, 3, 4]
10.2 递归
function myFlat (arr) {
let res = []; //res要定义在递归函数外
function fun(arr) {
arr.map(item => {
Array.isArray(item) ? fun(item) : res.push(item)
})
};
fun(arr);
return res;
}
10.3 reduce
function myFlate(arr) {
return arr.reduce((pre, cur) => {
return pre.concat(Array.isArray(cur) ? myFlate(cur) : cur )
}, []);
}
10.4 扩展运算符
while(arr.some(Array.isArray)) {
arr = [].concat(...arr)
}
11 sleep
function sleep(wait = 1000) {
return new Promise(resolve => setTimeout(resolve, timer));
}
12 双向数据绑定
12.1 defineProperty
Object.defineProperty (对象名,对象属性,属性描述器)
const data = { text: 'default' };
const input = document.getElementById('input');
const span = document.getElementById('span');
//数据挟持,数据变化 =》 修改视图
Object.defineProperty(data, 'text', {
configurable: true, //是否能被修改
enumerable: true, //是否可遍历
get() { //获取data 'text' 属性时候调用 get()且 data.text = 123;
return 123;
},
set(newVal) { //每次给对象属性赋值的时候会调用这个函数
input.value = newVal;
span.innerHTML = newVal;
}
});
//视图改变 =》数据变化
input.addEventListener('keyup', function(e) => {
data.text = e.target.value;
})
12.2 proxy
const data = { text: 'default' };
const input = document.getElmentById('input');
const span = document.getElmentById('span');
const handler = {
set(target, key, value) {
target[key] = value;
span.innerHTML = value;
return value;
}
}
const proxy = new Proxy(data, hanler);
input.addEventListener('keyup', function(e) {
proxy.text = e.target.value;
})