这些基本的js骚操作,你都会了吗?

735 阅读3分钟

引言


🦐🦐🦐

1. 实现一个 new 关键字

function _new(fn, ...args) {
    const obj = Object.create(fn.prototype); // 用fn原型创建一个对象obj
    const ret = fn.apply(obj, args); // 执行fn
    if((typeof ret === 'object'|| typeof ret ==='function')&&ret!==null){
        return ret;
    }
    return obj;
}

2. 多维数组展平

使用reduce实现:

const flatten = arr => arr.reduce((p,n)=>p.concat(Array.isArray(n)?flatten(n):n),[]);

使用flatMap实现:

const flatten = arr => arr.flatMap(item=>Array.isArray(item)?flatten(item):item)

使用flat实现:

const flatten = (arr) => arr.flat(Infinity);

使用迭代实现

// es5
function flatten(arr){
	var result = [];
	var stack = Array.prototype.slice.call(arr);
	while(stack.length){
		var item = stack.shift();
		if(Array.isArray(item)){
			Array.prototype.push.apply(stack,item);
		}else{
			result.push(item)
		}
	}
	return result;
}

// es6 
const flatten = arr =>{
    let result = [];
    let stack = [...arr];
    while(stack.length){
        if(Array.isArray(item)){
            stack.push(...item);
        }else{
            result.push(item);
        }
    }
    return result;
}

3. 防抖

描述:高频事件触发n秒内只执行一次,如果n秒内重复触发,则重新计算时间

/*
*   @param fn 需要防抖的函数
*   @param delay 时间间隔
*   @param immediately 第一次是否立即执行
*/
function debounce(fn,delay=500,immediately=true){
    let timer = null;
    let isFirstTime = true;
    return function(...args){
        clearTimeout(timer); // 重复触发时清除定时器
        if(isFirstTime&&immediately){
            fn.apply(this,args);
            isFirstTime = false;
        }else{
             timer=setTimeout(()=>{
                    fn.apply(this,args)
             },delay)
        }
    }
}

4. 节流

描述:高频函数在指定时间内只执行一次,重复触发也只执行一次,稀释函数的执行频率

/*
*   @param fn 需要节流的函数
*   @param delay 时间间隔
*   @param immediately 第一次是否立即执行
*/
function throttle(fn,delay=500,immediately=true){
    let lock = false;
    let isFirstTime = true;
    return function(...args){
        if(lock) return false; // 加锁
        lock = true;
        if(isFirstTime&&immediately){
            fn.apply(this,args);
            lock = false;
            return isFirstTime = false;
        }
        setTimeout(()=>{
            lock = false;
            fn.apply(this,args)
        },delay)
    }
} 

5. 深度克隆

深度克隆一个对象,只复制可枚举的属性,不包括不可枚举属性以及原型链

function getType(obj){
    return Object.prototype.toString.call(obj).slice(8,-1);
}
function cloneDeep(obj){
	let target = {};
	if(getType(obj)==='Object'){
			for(let key in obj){
				let item = obj[key];
				target[key]=cloneDeep(item);
			}
			return target;
	}
	if(getType(obj)==='Array'){
		return obj.map(item => cloneDeep(item) )
	}
	return obj;
}

6. 柯里化

当参数达到指定个数的时候执行方法,运用了递归与闭包

// es6
const curry = fn =>{
    const g = (...allArgs) =>allArgs.length>=fn.length?fn(...allArgs):(...args)=>g(...allArgs,...args);
    return g;
}

// es5
var currying = function(fn) {
       function c() {
         var allArgs = Array.prototype.slice.call(arguments,0);//保存所有的参数
        if (allArgs.length>=fn.length) { // 如果大于函数的参数长度则触发
          return fn.apply(this, allArgs); 
        } 
        return function(){ // 继续柯里化
            var args = Array.prototype.slice.call(arguments,0);
              return c.apply(this,allArgs.concat(args)); // 参数合并
        };
       }
       return c;
}

7. 简单的发布订阅

简单的实现发布订阅模式,不保证严谨性

class EventEmitter{
    events={}
    on(event,fn){
        if(event&&typeof fn === 'function'){
            this.events[event]||(this.events[event]=[]);
            this.events[event].push(fn);
        }else{
            throw new Error('params error');
        }
    }
    emit(event,...args){
        if(this.events[event]){
            this.events[event].forEach(fn=>fn(...args));
        }else{
            throw new Error(`There is not an event:${event} in EventEmitter,you should register it first`);
        }
    }
    
}

const Event = new EventEmitter();

Event.on('click',(a,b)=>{
    console.log('you click',`${a}-${b}`);
})

Event.emit('click','1','2'); // you click 1-2

Event.emit('touch'); // Error

8. lambda演算之Y组合子

Y 组合子是 lambda 演算中的一个概念,是任意函数的不动点,在函数式编程中主要作用是 提供一种匿名函数的递归方式。

const Y = f =>(x=>f(v=>x(x)(x)))(x=>f(v=>x(x)(v)))

9. js模拟实现call函数

Function.prototype.$call = function(target,...args) {
	if(target===null||target===void 0){
		target = window;
	}else{
	    target = Object(target);
	}
	
	 let fn = Symbol('__fn__');

	target[fn] = this;
	
	const ret = target[fn](...args);
	
	delete target[fn];

	return ret;
} 

10. 广度遍历bfs

    function bfs (tree) {
    var stack = [...tree];
    var res = [];
    while (stack.length) {
        var node = stack.shift();
        if(node.children){
			stack.push(...node.children);
		}
		console.log(node);
		res.push(node);
    }
    return res;
}

11. 深度遍历dfs

function dfs(tree){
	const queue = [...tree];
	const res = [];
	while(queue.length){
		const node = queue.shift();
		if(node.children){
			queue.unshift(...node.children);
		}
		console.log(node);
		res.push(node);
	}
	return res;
}

12. 反柯里 uncurring

Function.prototype.uncurring = function(){
    var self = this;
    return function(){
        var obj = Array.prototype.shift.call(arguments);
        return self.apply(obj,arguments);
    }
}

var push = Array.prototype.push.uncurring();
var obj={
    0:'1',
    1:'2',
    2:'3',
    length:3
}
push(obj,'4') // 输出

13. 高阶函数实现AOP

Function.prototype.before = function(fn){
    var self = this;
    return function(){
        fn.apply(this,arguments);
        return self.apply(this,arguments);
    }
}

Function.prototype.after = function(fn){
    var self = this;
    return function(){
        var ret = self.apply(this,arguments);
        fn.apply(this,arguments);
        return ret;
    }
}

// example
function a(i){
alert(i)
}
var $a = a.before(function(i){
    console.log(i)
    alert(0)
}).after(function(){
    alert(2)
})
$(1);

14. 函数式编程之-管道函数

  • f(g(k(v))): 嵌套地狱
  • 理想方法:fn(f,g,k)(v)
const pipe = (...fns) => (p) => fns.reduce((v,f) => f(v),p);
// ;

15. koa中间件原理

const delay = async () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve();
    }, 2000);
  });
}
// 中间间模拟
const fn1 = async (ctx, next) => {
  console.log(1);
  await next();
  console.log(2);
}
const fn2 = async (ctx, next) => {
  console.log(3);
  await delay();
  await next();
  console.log(4);
}
const fn3 = async (ctx, next) => {
  console.log(5);
}

const middlewares = [fn1, fn2, fn3];

// compose 实现洋葱模型
const compose = (middlewares, ctx) => {
  const dispatch = (i) => {
    let fn = middlewares[i];
    if(!fn){ return Promise.resolve() }
    return Promise.resolve(fn(ctx, () => {
      return dispatch(i+1);
    }));
  }
  return dispatch(0);
}

compose(middlewares, 1);

16. js继承

es5寄生组合:

function Super(){};// 父类
function Sub(){ // 子类
    Super.call(this);
};
function inherit(sub,sup){
    sub.prototype = Object.create(sup.prototype);// 继承原型
    sub.prototype.constructor = sub; // 改变
	Object.setPrototypeOf(sub,sup)
};
inherit(Sub,Super);
var sub = new Sub();
console.log(sub);

es6 class:

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y);
    this.color = color; 
  }
}

17.FVN hash函数

function hashFunction(key) {
    const str = String(key);
    let hash = 2166136261; // FNV_offset_basis (32 bit)
    for (let i = 0; i < str.length; i += 1) {
      hash ^= str.codePointAt(i); // XOR
      hash *= 16777619; // 32 bit FNV_prime
    }
    return (hash >>> 0) 
  }