bind,call,apply,防抖,節流,柯里化,惰性,記憶函數的javascript實現

call

Function.prototype.myCall = function () {
    //獲取this指向
    var _this = arguments[0];
    
    //兼容this指向爲原始值
    if (typeof _this == 'number') {
        _this = new Number(_this)
    } else if (typeof _this == 'boolean') {
        _this = new Boolean(_this)
    } else if (typeof _this == 'string') {
        _this = new String(_this)
    } else if (!_this) {
        //兼容瀏覽器和node
        try {
            _this = window;
        } catch (e) {
            _this = {};
        }
    }
    
    // 獲取參數
    var _arguments = [...arguments].slice(1);
    //掛載到this指向上面
    _this.fn = this;
    //使用eval執行這個新增的方法
    var result = eval('_this.fn(' + [..._arguments].join(',') + ')');
    //刪除該方法
    delete _this.fn;
    //返回執行結果
    return result;
}

複製代碼

apply

Function.prototype.myCall = function (_this, arr) {

    _this = _this;
    
    if (typeof _this == 'number') {
        _this = new Number(_this)
    } else if (typeof _this == 'boolean') {
        _this = new Boolean(_this)
    } else if (typeof _this == 'string') {
        _this = new String(_this)
    } else if (!_this) {
        try {
            _this = window;
        } catch (e) {
            _this = {};
        }
    }

    _this.fn = this;

    if (!arr) {
        var result = ctx.fn();
    } else {
        var result = eval('_this.fn(' + [...arr].toString() + ')');
    }
    delete _this.fn;
        return result;
}
複製代碼

bind

Function.prototype.myBind = function (target) {
    var self = this;
    //獲取參數
    var args = [].slice.call(arguments, 1);
    var fn = function () {
        var _arg = [].slice.call(arguments, 0);
        return self.apply(target, args.concat(_arg));
    }
    // 設置返回的新函數的函數的原型鏈
    fn.prototype.__proto__ = this.prototype
    return fn;
}
複製代碼

節流

  • 瘋狂觸發函數, 只有單位時間內好使一次。
function throttle(fn, delay) {
            var lock = false;
            return function () {
                if (!lock) {
                    fn(...arguments);
                    lock = true;
                    setTimeout(() => {
                        lock = false;
                    }, delay);
                }

            }
        }
複製代碼

防抖

  • 瘋狂觸發函數,只有第一次好使。
function debounce(fn, delay) {
     var lock = false;
     var timer = null;
     return function () {
         if (!lock) { //開鎖狀態下
             fn(...arguments);
             lock = true;
             timer = setTimeout(() => {
                 lock = false;
             }, delay);
         } else { //鎖啓用狀態下
             clearInterval(timer);
             timer = setTimeout(() => {
                 lock = false;
             }, delay);
         }
     }
 }
複製代碼

單層柯里化

//傳入想要進行柯里化處理的函數和前幾個參數
function fixedParam(fn) {
    var _arguments1 = [].slice.call(arguments, 1);
    return function () {
        var _arguments2 = [...arguments];
        fn.apply(this, [..._arguments1, ..._arguments2]);

    }
}

function sum(a, b, c, d) {
    console.log(a + b + c + d);
}
// 
var currySum = fixedParam(sum, 1, 2);
//下次執行輸入剩下的參數
currySum(3, 4);
複製代碼

多層柯里化1 (理解起來較難,比較繞)

function fixedParam(fn) {
    var _arguments1 = [].slice.call(arguments, 1);
    return function () {
        var _arguments2 = [...arguments];
        fn.apply(this, [..._arguments1, ..._arguments2]);
    }
}
function Curry(fn, length) {
    var len = length || fn.length;
    //採用閉包思想,第一次讀取參數總長度,
    return function () {
        console.log(arguments);  
        //每一次的參數都是獨立的
        if (arguments.length < len) {
            //當參數長度不足的時候,執行fixedParam,
            var combineArguments = [fn].concat(...arguments);
            // 參數會存入到fixedParam的AO的_arguments中
            var fixedFn = fixedParam.apply(this, combineArguments);
            // 還須要多少參數才能執行
            var needParams = len - arguments.length;
            // 遞歸返回函數
            return Curry(fixedFn, needParams);
        } else {
            //已經知足執行條件,執行
            return fn.apply(this, arguments);
        }
    }
}


function sum(a, b, c, d) {
    console.log(a + b + c + d);
}

var currySum = Curry(sum);

currySum(1)(2)(3)(4);
//argumnets 打印結果
/*
[Arguments] { '0': 1 }
[Arguments] { '0': 2 }
[Arguments] { '0': 3 }
[Arguments] { '0': 4 }
*/

複製代碼

多層柯里化2 (這種方式理解更容易些)

(function () {
    try {
        _this = window;
    } catch (e) {
        _this = this;
    }
    //兼容瀏覽器和node後端
    _this.Curry = Curry;
    //導出Curry方法
    
    //函數主體部分
     var _arguments = [];
    //參數列表
    function Curry(fn, length) {
        var len = length || fn.length;
        console.log(_arguments)
        return function () {
            _arguments = _arguments.concat([...arguments]);
            if (arguments.length < len) {
                return Curry(fn, len - arguments.length);
            } else {
                return fn.apply(this, _arguments);
            }
        }
    }
})()

function sum(a, b, c, d) {
    console.log(a + b + c + d);

}

var currySum = Curry(sum);

currySum(1, 2, 3)(4);
複製代碼

惰性函數處理事件綁定兼容ie8和w3c.

<body>
    <button id="button1"></button>
    <button id="button2"></button>
    <script>
        var oBtn1 = document.getElementById('button1');
        var oBtn2 = document.getElementById('button2');

        Element.prototype.addEvent = function (type, handle) {
            if (this.addEventListener) {
                this.addEventListener(type, handle);
                Element.prototype.addEvent = function (type, handle) {
                    console.log('您的瀏覽器是符合W3C標準的');
                    this.addEventListener(type, handle, false);
                }
            } else {
                //兼容 ie8
                this.attachEvent('on' + type, handle);
                Element.prototype.addEvent = function (type, handle) {
                    console.log('您的瀏覽器是不符合W3C標準的');
                    this.attachEvent('on' + type, handle)
                }
            }
        }
        oBtn1.addEvent('click', function () {
            console.log(this)
        })
        oBtn2.addEvent('click', function () {
            console.log(this)
        })
    </script>
</body>
複製代碼

記憶函數

function memorize(fn) {
    var cache = {};
    return function () {
        var key = arguments.length + '-' + Array.prototype.join.call(arguments, '-');
        if (cache[key]) {
            return cache[key];
        } else {
            return cache[key] = fn.apply(this, arguments);
        }
    }
}

function addToOne(n) {
    if (n == 1) return 1;
    return n + addToOne(n - 1);
}

var memorizeAddToOne = memorize(addToOne);
console.log(memorizeAddToOne(100));

複製代碼
相關文章
相關標籤/搜索