js权威指南_第八章函数_函数式编程示例代码学习

邹高懿
2023-12-01
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>函数式编程</title>
</head>
<body>
<h1>js权威指南</h1>
<p>第八章函数__函数式编程示例代码学习</p>
<script>
//8.8.1使用数组处理函数
//计算数组元素的平均值和标准差
//非函数式编程
function fn1(){
    var data=[1,1,3,5,5];
    var total=0;
    for(var i=0;i<data.length;i++){
        total+=data[i];
    }
    var mean=total/data.length;//平均数
    console.log(mean);//=>3

    //标准差是反映一组数据离散程度最常用的一种量化形式,是表示精确度的重要指标。
    //所有数减去其平均值的平方和,所得结果除以该组数之个数(或个数减一,即变异数),再把所得值开根号,所得之数就是这组数据的标准差。

    var t=0;
    for(var i=0;i<data.length;i++){
        var deviation=data[i]-mean;
        t+=deviation*deviation;
    }
    var stddev=Math.sqrt(t/(data.length-1));//标准差
    console.log(stddev)//=>2
}

//fn1();

//使用数组方法map()和reduce()计算数组元素的平均值和标准差
function fn2(){
    var data=[1,1,3,5,5];
    var sum=function(x,y){return x+y};
    var square=function(x){return x*x};
    //reduce() 使用指定的函数(称为化简函数),将数组元素进行组合,合成单个值返回。
    var mean=data.reduce(sum)/data.length;
    console.log(mean);//=>3
    //map() 从头到尾遍历数组,为每个元素调用指定的函数,指定函数的返回值(必须)组成新的数组。
    var deviationArr=data.map(function(x){return mean-x});
    var stddev=Math.sqrt(deviationArr.map(square).reduce(sum)/(data.length-1));
    console.log(stddev)//=>2
}

//fn2();

//8.8.2 高级函数
function fn3(){
    //高阶函数not()返回一个新的函数odd,odd将它的实参传入f(even),odd再返回f(even)的返回值的逻辑非。
    function not(f){
        return function(){//返回一个新函数
            //apply() 允许显示指定调用所需的this值,即,任何函数可以作为任何对象的方法来调用,哪怕这个函数不是这个对象的方法。
            //apply()方法要求以数组的形式传入参数。
            var result= f.apply(this,arguments);//调用f()
            return !result;//对结果求反
        }
    }

    var even=function(x){//判断是否为偶数
        return x%2 === 0;
    };

    var odd=not(even);//判断是否是奇数
    var arr=[1,1,3,5,5];
    console.log(arr.every(odd));//true
}

//fn3();

//例2
//自定义数组 map() 方法
var map=Array.prototype.map
?function(a,f){return a.map(f)}
:function(a,f){
    var results=[];
    for(var i= 0,len= a.length;i<len;i++){
        //undo:不明白这里为啥需要判断 i in a
        if(i in a){
            //call()方法允许显示指定调用所需的this值,即,任何函数可以作为任何对象的方法来调用,哪怕这个函数不是这个对象的方法。
            //call()方法使用它自有的实参列表作为函数的实参
            results[i]= f.call(null,a[i],i,a)
        }
    }
    return results;
};

function fn4(){
    //mapper()产生一个新函数,新函数将一个数组映射到另一个使用这个函数的数组上。
    function mapper(f){
        return function(a){
            return map(a,f);
        };
    }
    var increment=function(x){return x+1;};
    var incrementer=mapper(increment);

    console.log(incrementer([1,2,3]));//=>[2,3,4]
}

//fn4();

//8.8.3不完全函数
//不完全函数是一种函数变换技巧,即把一次完整的函数调用拆分成多次函数调用,每次传入的实参都是完整实参的一部分,每个拆分开的函数叫做不完全函数,每次函数调用叫做不完全调用。

function fn5(){
    //实现一个工具函数将类数组对象或对象转为真正的数组
    function array(a,n){
        //slice() 返回指定数组的一个片段或子数组。含头不含尾,end 可为负。end 省略截取到末尾。
        return Array.prototype.slice.call(a,n || 0);
    }

    function partialLeft(f){
        var args=arguments;
        return function(){
            var a=array(args,1);//开始处理外部第一个args
            a= a.concat(array(arguments));//然后增加所有的内部实参
            return f.apply(this,a);//然后基于这个实参列表调用f()
        }
    }

    var f=function(x,y,z){return x*(y-z);};

    console.log(partialLeft(f,2)(3,4));//=>2*(3-4)=-2
}

//fn5();

//8.8.4记忆
//memorize()接收一个函数作为实参,并返回带有记忆能力的函数。
function memorize(f){
    var cache={};//将值保存在闭包里
    return function(){
        //将实参转换为字符串,并将其用做缓存的键
        //join() 将数组中所有元素转为字符串并按指定的分隔符(默认逗号)连接在一起,返回最后生成的字符串。
        var key=arguments.length + Array.prototype.join.call(arguments,",");
        if(key in cache){
            return cache[key];
        }else{
            return cache[key] = f.apply(this,arguments)
        }
    };
}

function fn6(){
    //定义一个阶乘函数,将上次的计算结果缓存。
    //注意:当我们写一个递归函数时,往往需要实现记忆功能。我们更希望调用实现了记忆功能的递归函数,而不是原递归函数。
    var factorial=memorize(function(n){
        return (n <= 1) ? 1 : n * factorial(n-1);
    });

    console.log(factorial(5));//=>5*4*3*2*1=120
}

fn6();

</script>
</body>
</html>
 类似资料: