function deboundce(f, delay){
let timer;
return function(...args){
if(timer) clearTimeout(timer);
timer = setTimout(()=>{
f.apply(this, args);
}, delay);
}
}
//定时器
function throttle(f, delay){
let timer;
return function(...args){
if(timer) return;
timer = setTimeout(()=>{
f.apply(this, args);
timer = null;
}, delay);
}
}
//date对象
function throttle(f, delay){
let pre = 0;
return function(...args){
let now = new Date();
if(now - pre > delay){
f.apply(this, args);
pre = now;
}
}
}
function myNew(f, ...args){
let obj = {};
obj.__proto__ = f.prototype;
f.apply(obj, args);
return obj;
}
function myInstanceof(a, b){
let ap = a.__proto__;
let bp = b.prototype;
while(ap){
if(ap === bp){
return true;
}
ap = ap.__proto__;
}
return false;
}
Function.prototype.myCall = function(obj, ...args){
obj = obj || window;
const fn = Symbol();
obj[fn] = this;
const res = obj[fn](...args);
delete obj[fn];
return res;
}
Function.prototype.myApply = function(obj, args){
obj = obj || window;
const fn = new Symbol();
obj[fn] = this;
const res = obj[fn](...args);
delete obj[fn];
return res;
}
Function.prototype.myBind = function(obj, ...args){
obj = obj || window;
const _this = this;
const res = function(...innerArgs){
if(this instanceof res){
_this.apply(this, [...args, ...innerArgs]);
}else{
_this.apply(obj, [...args, ...innerArgs]);
}
};
res.prototype = _this.prototype;
return res;
}
//原型链继承
/*
缺点:1、想为子类添加属性和方法,必须在new语句之后。
2、创建子实例时,无法向父实例传参。
3、不支持多继承。
*/
function Children(){};
Children.prototype = new Father();
Children.prototype.name = 'a';
//构造继承
/*
缺点:1、子类实例不是父类实例。
*/
function Children(name){
Father.call(this);
this.name = name;
}
//实例继承
/*
缺点:1、实例是父类实例,不是子类实例。
2、不支持多继承。
*/
function Children(name){
let instance = new Father();
instance.name = name;
return instance;
}
//拷贝继承
/*
缺点:1、效率低。
2、无法获取父类的不可枚举属性。
*/
function Children(name){
let father = new Father();
for(let p in father){
this.prototype[p] = father[p];
}
this.name = name;
}
//组合继承(构造继承+原型链继承)
/*
缺点:调用两次父类构造函数,生成两份实例。
*/
function Children(name){
Father.call(this);
this.name = name;
}
Children.prototype = new Father();
Children.constructor = Children;
//寄生组合继承
function Children(name){
Father.call(this);
this.name = name;
}
let Super = function(){};
Super.prototype = Father.prototype;
Children.prototype = new Super();
//class继承
/*
不是所有的浏览器都支持。
*/
class Father{
constructor(name, age){
this.name = name;
this.age = age;
}
}
class Children extend Father{
constructor(name, age, color){
super(name, age);
this.color = color;
}
}
//new
var obj = new Object()l
obj.name = 'tom';
//字面量
var obj = {
name: 'tom'
};
//工厂模式
function createObj(name, age){
var obj = {
name: name,
age: age
};
return obj;
}
//构造函数
function obj(name, age){
this.name = name;
this.age = age;
}
//构造函数+原型
function obj(name, age){
this.name = name;
this.age = age;
}
obj.prototype.setName = function(){};
function addMethod(object, name, fn){
var old = object[name];
object[name] = function(){
if(fn.length === arguments.length){
return fn.apply(this, arguments);
}else if(typeof old === 'function'){
return old.apply(this, arguments);
}
}
}
为什么要用setTimeout模拟setInterval?
- 因为setInterval不一定准时。
function mysetInterval(fn, delay){
let timer = null;
function interval(){
fn();
timer = setTimout(interval, delay);
}
interval();
return {
cancel: ()=>{
clearTimeout(timer);
}
}
}
//setInterval模拟setTimeout
function mysetTimeout(fn, delay){
let timer = setInterval(()=>{
clearInterval(timer);
fn();
}, delay);
}
// 实现1
const add = (a, b, c) => a + b + c;
const a = currying(add, 1);
console.log(a(2, 3)); // 6
function currying(fn, ...args1){
let args = [...arg1];
const res = (...args2) => {
args = [...args, ...args2];
if(args.length === fn.length){
return fn(...args);
}else{
return res;
}
}
return res;
}
//实现2
console.log(sum(1)(2)()); // 3
console.log(sum(1,2,3)(4)());// 10
function sum(...args1){
let args = [...args1];
const res = (...args2) => {
if(!args2.length) return res.toString();
args = [...args, ...args2];
return res;
};
res.toString = () => args.reduce((pre, nex) => pre + nex);
return res;
}
Promise/A+规范
class myPromise{
constuctor(executor){
this.initValue();
this.initBind();
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
//throw
try{
executor(this.resolve, this.reject);
}catch(e){
this.reject(e);
}
}
initValue(){
this.PromiseState = 'pending';
this.PromiseResult = null;
}
initBind(){
this.resolve = this.resolve.bind(this);
this.reject = this.reject.bind(this);
}
resolve(value){
//状态不可变
if(this.PromiseState !== 'pending') return;
this.PromiseState = 'fullfilled';
this.PromiseResult = value;
//清空
while(this.onFulfilledCallbacks.length){
this.onFullfilledCallbacks.shift()(this.PromiseResult);
}
}
reject(reason){
if(this.PromiseState !== 'pending') return;
this.PromiseState = 'rejected';
this.PromiseResult = reason;
while(this.onRejectedCallbacks.length){
this.onRejectedCallbacks.shift()(this.PromiseResult);
}
}
then(onFulfilled, onRejected){
//参数检验
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val;
onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason};
//链式调用
var thenPromise = new myPromise((resolve, reject)=>{
const resolvePromise = cb =>{
//setTimeout模拟微任务(?
//queueMicrotask
setTimeout(()=>{
try{
const x = cb(this.PromiseResult);
if(x === thenPromise){
throw new Error('循环引用出错啦');
}
if(x instanceof myPromise){
//是promise对象
//返回值为成功,新promise就是成功
//返回值为失败,新promise就是失败
x.then(resolve, reject);
}else{
//非promise直接成功
resolve(x);
}
}catch(err){
reject(err);
throw new Error(err);
}
})
}
if(this.PromiseState === 'fulfilled'){
resolvePromise(onFulfilled);
}else if(this.PromiseState === 'rejected'){
resolvePromise(onRejected);
}else if(this.PromiseSate === 'pending'){
//定时器,暂存
this.onFulfilledCallbacks.push(onFulfilled.bind(this));
this.onRejectedCallbacks.push(onRejected.bind(this));
}
});
return thenPromise;
}
all(promises){
//接受一个Promise数组,其中如果有非Promise项,则此项当作成功。
//如果所有的promise都成功,则返回成功结果数组
//如果有一个promise失败,则返回这个失败结果
return new myPromise((resolve, reject)=>{
let count = 0;
let result = [];
const len = promises.length;
if(len === 0) return resolve([]);
promises.forEach((p, i)=>{
//有的不是Promise对象,转化一下
myPromise.resolve(p).then(res=>{
//保存结果
result[i] = res;
count ++;
//等于数组长度,返回
if(count === len) resolve(result);
//有一个失败,整个失败
}).catch(reject);
})
})
}
race(promises){
//接受一个Promise数组,其中如果有非promise项,则此项当作成功。
//哪个promise最快得到结果,就返回那个结果。
return new myPromise((resolve, reject)=>{
promises.forEach(p=>{
//转换
MyPromise.resolve(p).then(resolve).catch(reject);
})
})
}
allSettled(promises){
//接受一个Promise数组,其中如果有非promise项,则此项当作成功。
//把每个promise的结果合并成数组返回。
return new myPromise((resolve, reject)=>{
let count = 0;
let result = [];
const len = promises.length;
if(len === 0) return res([]);
promises.forEach((p, i)=>{
myPromise.resolve(p).then(res=>{
result[i] = {
status: 'fulfilled',
value: res
};
count ++;
if(count === len){
resolve(result);
}
}).catch(err=>[
result[i] = {
status: 'rejected',
value: err
};
count++;
if(count === len){
resolve(result);
}
])
});
})
}
any(promises){
//接受一个Promise数组,其中如果有非Promise项,则此项当作成功。
//如果所有的promise都失败,则报错
//如果有一个promise成功,则返回这个成功结果
return new myPromise((resolve, reject)=>{
let count = 0;
const len = promises.length;
if(len === 0) return reject([]);
promises.forEach((p, i)=>{
myPromise.resolve(p).then(res=>{
resolve(res);
}).catch(err=>{
count++;
if(count === len){
reject(new AggregateError('All promises were rejected'))
}
})
});
})
}
}
const obj1 = { name: 'a' };
// Object.assign
const obj2 = Object.assign({}, obj1);
// ...扩展运算符
const obj2 = {...obj1};
//拷贝函数等其他引用类型,循环引用时存在缺陷。
JSON.parse(JSON.stringfy(obj));
//只实现了拷贝基本数据类型、可遍历引用数据类型array、object。
function deepClone(obj, map = new WeakMap()){
if(typeof obj !== 'object' || obj === null) return obj;
let result = Array.isArray(obj)? [] : {};
if(map.get(obj)){
return map.get(obj);
}
map.set(obj, result);
Reflet.ownKeys(obj).forEach(key=>{
result[key] = deepClone(obj[key], map);
});
return result;
}
class EventEmitter{
constructor(){
this.events = {};
}
//实现订阅
on(key, callback){
if(!this.events[key]){
this.events[key] = [callback];
}else{
this.events[key].push(callback);
}
}
//删除订阅
off(key, callback){
if(!this.events[key]) return;
this.events[key] = this.events[key].filter(item=>item!==callback);
}
//触发事件
emit(key, ...rest){
this.events[key] &&
this.events[key].forEach(event => event.apply(this, rest));
}
//只执行一次订阅事件
once(key, callback){
function fn(){
callback();
this.off(key, fn);
}
this.on(key, fn);
}
}
class Notify{
constructor(){
this.observerList = [];
}
add(obj){
this.observerList.push(obj);
}
remove(obj){
const idx = this.observerList.findIndex(v=>v===obj);
if(idx !== -1){
this.observerList.splice(idx, 1);
}
}
notify(){
this.observerList.forEach(item =>{
item.update();
});
}
}
class Watch{
constructor(name){
this.name = name;
}
update(){
console.log(this.name);
}
}
function unique(arr){
return [...new Set(arr)];
}
function unique(arr){
return arr.filter(function(item, index, array){
return array.indexOf(item) === index;
});
}
function flatten(arr){
while(arr.some(item => Array.isArray(item))){
arr = [].concat(...arr);
}
return arr;
}
function flatten(arr){
let result = [];
for(let i = 0, len = arr.length; i < len; i ++){
if(Array.isArray(arr[i]){
result = result.concat(flatten(arr));
}else{
result.push(arr[i]);
}
}
return result;
}
const obj = {
a: {
b: 1,
c: 2,
d: {e: 5}
},
b: [1, 3, {a: 2, b: 3}],
c: 3
};
console.log(flatten(obj));
// {
// 'a.b': 1,
// 'a.c': 2,
// 'a.d.e': 5,
// 'b[0]': 1,
// 'b[1]': 3,
// 'b[2].a': 2,
// 'b[2].b': 3
// c: 3
// }
function isObject(val){
return typeof val === 'object' && val !== null;
}
function flatten(obj){
if(!isObject(obj)){
return;
}
let res = {};
const dfs = (cur, prefix) => {
if(isObject(cur)){
if(Array.isArray(cur)){
cur.forEach((item, index)=>{
dfs(item, `${prefix}[${index}]`);
});
}else{
for(let k in cur){
dfs(cur[k], `${prefix}${prefix ? '.' : ''}${k}`);
}
}
}else{
return res[prefix] = cur;
}
};
dfs(obj, '');
return res;
}
const arrayLike = document.querySelectorAll('div');
// 扩展运算符
[...arrayLike]
// Array.from
Array.from(arrayLike)
// slice:不传参数时,会返回原数组的拷贝
Array.prototype.slice.call(arrayLike)
// concat
Array.prototype.concat.apply([], arrayLike);
// 实现
const obj = [
{
id: 1,
text: '节点1',
parentId: 0 //这里用0表示为顶级节点
},
{
id: 2,
text: '节点1_1',
parentId: 1 //通过这个字段来确定子父级
}
]
console.log(toTree(obj));
// [
// {
// id: 1,
// text: '节点1',
// parentId: 0,
// children: [
// {
// id:2,
// text: '节点1_1',
// parentId:1
// }
// ]
// }
// ]
function toTree(data){
let res = [];
let map = new Map();
data.forEach(node =>{
map.set(node.id, node);
})
map.forEach((value, key)=>{
if(+value.parentId !== 0){
let parent = map.get(value.parentId);
if(!parent.children){
parent.children = [];
}
parent.children.push(value);
}else{
res.push(value);
}
});
return res;
}
// 实现
const obj = [
{
id: 1,
text: '节点1',
parentId: 0,
children: [
{
id:2,
text: '节点1_1',
parentId:1
}
]
}
];
console.log(toArr(obj));
// [
// {
// id: 1,
// text: '节点1',
// parentId: 0 //这里用0表示为顶级节点
// },
// {
// id: 2,
// text: '节点1_1',
// parentId: 1 //通过这个字段来确定子父级
// }
// ...
// ]
function toArr(data){
let res = [];
const dfs = (tree)=>{
tree.forEach(item => {
if(item.children){
dfs(item.children);
delete item.children;
}
res.push(item);
});
}
dfs(data);
return res;
}