资讯专栏INFORMATION COLUMN

javascript招式总结

mingde / 1513人阅读

摘要:模块的私有变量是预先定义好的,而柯里化是保存第一次调用时传入的参数为私有变量。

前言

在平时的开发中,经常会遇到一些特殊情况,就需要一些招式来应对。这里总结一下自己常用到的一些小招式,有不足欢迎大家指出。

模块
    var fuc1 = (function() {
        var a = "hello ";
        return function(str) {
            return a + str;
        }
    })()
    fuc1("world"); // hello world

模块模式的一般形式是:一个定义了私有变量和函数;利用闭包创建可以访问私有变量和函数的特权函数;最后返回这个特权函数,或者把它们保存到一个可访问的地方。

该招式有以下应用场景

协调异步

代码需要在两个异步fuc1fuc2都执行结束后再执行,

var manager = (function() {
    var count = 0;
    return function() {
        if(++count === 2){
            // logic 3
        }
    }
})()
function fuc1() {
    //...
}
function fuc2() {
    //...
}
setTimeout(function() {
   fuc1();
   manager();
}, 10)
setTimeout(function() {
   fuc2();
   manager();
}, 10)
兼容测试
var createXHR = (function () {
    if(typeof XMLHttpRequest != "undefined") {
        return function () {
            return new XMLHttpRequest();
        }
    }else if(typeof ActiveXObject != "undefined") {
        return function () {
            if(typeof arguments.callee.activeXString != "string") {
                var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"],
                    i,len;
                for(1 = 0, len = versions.length; i < len; i++){
                    try{
                        new ActiveXObject(versions[i]);
                        arguments.callee.activeXString = versions[i];
                        break;
                    }catch(ex){
                        // ...
                    }
                }
            }
            return new ActiveXObject(arguments.callee.activeXString);
        }
    }else{
        return function() {
            throw new Error("NO XHR object available.");
        }
    }
})();
利用私有变量
var parse = (function() {
    var config = ["I", "II", "III", "IV"];
    return function(num) {
        return config[num - 1]
    }
})()
parse(1); // I
parse(4); // IV
柯里化

柯里化听起来很高大上,然而也就是Currying的音译,千万别被名称吓跑了。
它是把接受多个参数的函数中的参数拆分成两次调用来传递并返回结果的新函数。
举一个简单的例子理解一下:

var add = function(a, b) {
    return a + b
}
add(1, 2) // 3

var currying = function(a) {
    return function(b) {
        return a + b
    }
}
currying(1)(2) // 3

add 为 接受多个参数的函数,currying是将add中的参数分两次调用传入并返回结果的新函数。

仔细想想,它其实是模块的衍生招式。模块的私有变量是预先定义好的,而柯里化是保存第一次调用时传入的参数为私有变量。因此它俩的区别是私有变量定义时机不同

下面是一个利用柯里化实现的累加方法

var currying = function (fn) {
    var args = [];
    return function () {
        var innerArgs = Array.prototype.slice.call(arguments);
        if(innerArgs.length === 0){
            return fn.apply(null, args)
        }
        args = args.concat(innerArgs);
        return arguments.callee;
    }
}

var mutil = function () {
    var num = 0, i = 0;
    while(arguments[i]){
        num += arguments[i++]
    }
    return num
}

var add = currying(mutil);

add(1,2)(3);
add(4);

add();  // 10
函数节流

某些代码不可以在没有间断的情况下连续重复执行,所有就需要节流。比如:拖动某DOM元素时,需要动态改变元素的 x y ,就需要用到节流函数了。

function throttle(method, delay) {
    var timer = null;
    return function () {
        var that = this, args = arguments;
        clearTimeout(method.tId);
        timer = setTimeout(function () {
            method.apply(that, args);
            clearTimeout(timer);
        }, delay);
    }
}
window.onresize = throttle(resizeHandle, 50)

使用该函数时你会发现一个问题:不断拖动元素的过程中元素是不动的,只有停顿一下元素才跟着动。
这样的体验很糟糕,为了提高性能、改善体验,需要升级一下节流函数。设置一个最大时间间隔来确保在拖动的过程中,元素可以跟随移动。

function throttle(method, context, delay, maxInterval) {
    var _start,_diff,timer;
    return function () {
        var that = this,
            args = arguments,
            _now  = +new Date();
        clearTimeout(timer);
        _start || (_start = _now);
        if(_now - _start >= maxInterval){
            method.apply(that, args)
        }else{
            timer = setTimeout(function () {
                method.apply(that, args)
            }, delay)
        }
    }
}
window.onresize = throttle(resizeHandle, 50, 100)
延迟加载处理

在业务中经常会遇到一些不需要同步处理的,又比较耗时的逻辑。对于这些逻辑可以采用数据分块(array chunking)的技术,小块小块地处理数组,通常每次一小块。可以创建一个“待办事项”队列,然后使用定时器逐个取出“事项”,接着设置另一个定时器。

function chunk(array, process, context) {
    setTimeout(function() {
        var item = array.shift();
        process.call(context, item);

        if(array.length > 0){
            setTimeout(arguments.callee, 100);
        }
    }, 100)
}
记忆函数

函数可以将先前操作的结果记录在某个对象里,从而避免重复运算,比如计算阶乘函数。

function memoizer(memory, handle) {
    return function (n) {
        var result = memory[n],
            recur  = arguments.callee;
        // 已运算过则直接返回
        if(!result){
            result = handle(recur ,n);
            memory[n] = result;
        }
        return result;
    }
}

var memory    = [1, 1],
    factorial = memoizer(memory, function (recur, n) {
        return n * recur(n - 1)
    });

factorial(4);

console.log(memory);  // [1, 1, 2, 6, 24]

(未完待续......)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/81148.html

相关文章

  • Vim修炼秘籍之语法篇

    摘要:建议先熟悉一遍修炼秘籍之命令篇,本秘籍食用更佳正文核心秘诀功法之究极总结操作次数操作行为操作范围下面,我会将此秘诀亲自传授于你。 前言 少年,我看你骨骼精奇,是万中无一的武学奇才,维护世界和平就靠你了,我这有本秘籍《Vim修炼秘籍》,见与你有缘,就十块卖给你了! 如果你是一名 Vimer,那么恭喜你,你的 Vim 技能马上要升级了 ?! 如果你之前不了解过 Vim ,那么也没关系,本文...

    hikui 评论0 收藏0
  • 【Vue原理】Vue源码阅读总结大会 - 序

    摘要:扎实基础幸好自己之前花了大力气去给自己打基础,让自己现在的基础还算不错。 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【2.5.17】 如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也可以吧 【Vue原理】Vue源码阅读总结大会 - 序 阅读源码是需...

    Edison 评论0 收藏0

发表评论

0条评论

mingde

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<