js權威指南_第八章函數_函數式編程示例代碼學習

<!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>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章