JS高阶编程的应用

243 阅读4分钟

单例设计模式

概念:用单独的实例来管理当前事务的相关特征(属性和方法),类似于实现一个分组的特点,而此时命名的obj等不仅仅叫做一个对象,也被称为命名空间。

基于闭包管控的单例模式称为:高级单例模式,以此来实现早期的模块划分(最早的模块化思想);

let module = (function(){
    function query(){}
    function tools(){}
    return {
        name:'test',
        tools:tools
    }
})();

惰性思想 (函数重构)

//下面方法只判断一次,不需要执行几次就重复判断几次
function getCss(el,attr){
    //'name' in obj——检测当前属性name是否为obj的一个属性
    if('getComputedStyle' in window){
        getCss = function (el,attr){
            return window.getComputedStyle(el)[attr];
        }
    }else{
        getCss = function (el,attr){
            return el.currentStyle[attr];
        }
    }
    return getCss(el,attr);
}

getCss(document.body,'margin');
getCss(document.body,'padding');
getCss(document.body,'width');

柯理化函数

概念:利用闭包的保存机制,把一些信息预先存储下来(预处理的思想);

let res = fn(1,2)(3);
console.log(res); //=>6  1+2+3

解析:fn(1,2)先执行,紧接着执行..(3),那么fn(1,2)需要返回一个函数去执行,所以return function(){...}

function fn(...outer){
    return function anonymous(...inner){
        let params = outer.concat(inner);  //外层和里层函数传递的所有值都合并在一起
        return params.reduce((n,item)=>{
           return n + item; 
        },0)
    }
}

知识延申:reduce

//不传递第二个实参值
let arr = [1,2,3,4,5];
let res = arr.reduce((n,item)=>{
    console.log(n,item);   
    //第一次输出:1  2    第一次触发回调函数执行,n是第一项,item是第二项
    //第二次输出:3  3    第二次触发回调函数执行,n是上一次回调函数的返回结果,item继续向后遍历数组项
    //第三次输出:6  4    ...
    //第四次输出:10 5    第 m 次触发回调函数执行,n是 m-1 次回调函数的返回结果
    return n+item;  //return信息会作为下一次回调函数执行n的结果
})


//传递第二个实参值
let arr = [1,2,3,4,5];
let res = arr.reduce((n,item)=>{
    console.log(n,item);   
    //第一次输出:0  1    第一次触发回调函数执行,n是第二个参数值,item是数组第一项
    //第一次输出:1  2    第二次触发回调函数执行,n是上一次回调函数的返回结果,item继续向后遍历数组项
    //第二次输出:3  3    ...
    //第三次输出:6  4    ...
    //第四次输出:10 5    第 m 次触发回调函数执行,n是 m-1 次回调函数的返回结果
    return n+item;  //return信息会作为下一次回调函数执行n的结果
},0)

回调函数:把一个函数作为值传递给另外一个函数,在另外一个函数中把这个函数执行(这是实现函数式编程重要的知识);

  • 函数式编程:注重结果,不在乎过程,过程交给别人处理;(利用reduce去累加)
  • 命令式编程:注重过程,需要自己去实现过程;(自己去编写累加)

compose思想

compose组合函数,把多层函数嵌套调用扁平化。

/*
  ---------------------------------------------问题描述---------------------------------------------
  在函数式编程当中有一个很重要的概念就是函数组合, 实际上就是把处理数据的函数像管道一样连接起来, 然后让数据穿过管道得到最终的结果。 例如:
    const add1 = (x) => x + 1;
    const mul3 = (x) => x * 3;
    const div2 = (x) => x / 2;
    div2(mul3(add1(add1(0)))); //=>3

    而这样的写法可读性明显太差了,我们可以构建一个compose函数,它接受任意多个函数作为参数(这些函数都只接受一个参数),然后compose返回的也是一个函数,达到以下的效果:
    const operate = compose(div2, mul3, add1, add1)
    operate(0) //=>相当于div2(mul3(add1(add1(0)))) 
    operate(2) //=>相当于div2(mul3(add1(add1(2))))

    简而言之:compose可以把类似于f(g(h(x)))这种写法简化成compose(f, g, h)(x),请你完成 compose函数的编写 
*/


/*
	------------------------------------------分析-------------------------------------------------
	compose函数执行后还可以继续执行,那么compose函数返回的是一个函数。
*/

const fn1 = x => x+10;
const fn2 = x => x-10;
const fn3 = x => x*10;
const fn4 = x => x/10;

function compose(...funcs){
    //funcs:存储按照顺序执行的函数(数组) ------ [fn1,fn3,fn2,fn4]
    return function anonymous(...args){
        //args:存储第一个函数执行需要传递的实参信息(数组) ------ [10]
        
        if(funcs.length===0) return args;
        if(funcs.length===1) return funcs[0](...args);
        return funcs.reduce((n,item)=>{
           //第一次n:第一个函数执行的实参   item是第一个函数
           //第二次n:上一次item执行的返回值,作为实参传递给下一个函数执行
           return Array.isArray(n) ? item(...n) : item(n) ;
        },args)
    }
}

let res = compose(fn1,fn3,fn2,fn4)(10);
console.log(res);