JS高階編程之柯理化函數

柯理化函數編程:
一個大函數執行,返回一個小函數。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>柯理化函數</title>
    <style>
        .box {
            background: red;
            height: 100px;
            width: 100px;
        }
    </style>
</head>

<body>
    <div class="box" id="box">柯理化函數</div>
    <script>
        //柯理化思想重寫bind:ES6版柯理化函數思想,類似實現一個模擬的this
        // ~ function (proto) {
        //     function bind(context = window, ...outerArgs) {
        //         // this:要處理的函數
        //         let _this = this; //將要處理的函數保留下來
        //         return function proxy(...innerArgs) {
        //             // this:將這個proxy綁定給誰就是誰
        //             let args = outerArgs.concat(innerArgs); //拼接事件對象和參數
        //             _this.call(context, ...args)
        //         }
        //     };
        //     proto.bind = bind;
        // }(Function.prototype)
        // fn.bind(); //這是調用自己定義bind

        // 處理兼容,兼容所有瀏覽器:
        // ~ function (proto) {
        //     function bind(context) {
        //         var context = context || window;
        //         var _this = this;
        //         var outerArgs = Array.prototype.slice.call(arguments, 1);
        //         return function proxy() {
        //             var innerArgs = [].slice.call(arguments, 0);
        //             // this:將這個proxy綁定給誰就是誰
        //             let args = outerArgs.concat(innerArgs); //拼接事件對象和參數
        //             _this.apply(context, args); //apply 傳的是一個數組
        //         }
        //     };
        //     proto.bind = bind;
        // }(Function.prototype)


        let obj = {
            x: 100
        }
        function fn(y) {
            // console.log(y)
            this.x += y;
            console.log(this);
        }
        box.onclick = fn.bind(obj, 200);
        //=> 即 box.onclick = function proxy(ev) { //弱項把ev事件對象傳過去,就加一個這個參數
        //_this.call(context, ...outerArgs);
        //=>即是這樣:
        // fn.call(obj, ...[200, ev])
        // }


        /*
        *  柯理化函數的思想:
        *     利用閉包的機制,把一些內容事先存儲和處理了,等到後期需要的時候,拿來即用即可。
        */

        /*
        *  bind:預先處理內容:
        *   @params:
        *     func: 要執行的函數
        *     context:要改變的this指向   
        *     ...args:給函數傳遞的參數
        *   @return:
        *       返回一個代理函數    
        *
        */

        // 真實項目中經常使用柯理化思想,大函數存儲一些值,供以後給小函數調用,利用閉包機制。,redux中的源碼很多就是使用的柯理化函數思想
        // 這是需要掌握的,執行大函數,返回小函數
        function bind(func, context, ...args) {
            // => func: fn
            // => context: obj
            // => ...args: [200,300]
            return function proxy() {
                func.call(context, ...args);
            };
        }

        // 1秒鐘後執行這個函數
        // setTimeout(function(){
        //     fn.call(obj, 200);
        // }, 1000); 
        // ==>修改爲:
        setTimeout(bind(fn, obj, 200), 1000);
        // => setTimeout(function proxy(){
        //      func.call(context,...args)
        //      => fn.call(obj,200,300)
        // },1000)


        // 不使用bind,可以使用如下方式:
        box.onclick = function () {
            //點擊執行匿名函數,在匿名函數執行的時候再把fn執行 
            fn.call(obj, 200);
        }

        // 觸發盒子點擊事件的時候,把fn執行,並且讓fn的this指向obj,再給fn傳遞一個值200
        // box.onclick = fn; => this指向obj,y => MouseEvent {isTrusted: true, screenX: 766, screenY: 200, clientX: 51, clientY: 68, …}
        // call/apply都會把函數立即執行,bind不會立即執行函數,預先存儲一些內容。(bind不兼容IE8及以下)
        // box.onclick = fn.call(obj, 200); //會立即執行
        // box.onclick = fn.bind(obj, 200);
    </script>
</body>

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