编写高效188js代码

阅读了<编写高质量代码: 改善js程序的188个建议>后, 摘录了一些好的例子,记录之….

惰性载入函数

    var addEvent = function(el, type, handle) {
        // 先判断事件兼容问题
        addEvent = el.addEventListener ? function(el, type, handle) {
            el.addEventListener(type, handle, false);
        } : function(el, type, handle) {
            el.attachEvent("on" + type, handle);
        };
        // 由于前面修改了addEvent的函数, 所以必须重新执行一次
        // 在函数内部改变自身的方式
        addEvent(el, type, handle);
    }

函数绑定

    function bind(fn, context) {
        return fn.apply(context, arguments);
    }

高阶函数

function map(array, fn) {
    var res = [];
    for(var i = 0, len = array.length; i < len; i++) {
        res.push(fn(array[i]);
    }
}

var mapped =map([1, 3, 5, 7], function(n) {
    return n = n + 1;
});                   // [2, 4, 6, 8]

函数节流

  • 应用环境 规定一个事件在指定的时间只能被调用一次
  • 例如监听窗口resize的事件 会直到用户停止拖动才会响应事件

    var processor = {
        // 在规定间隔内只能执行一次
        timeoutId : 0,
            // 实际进行处理的方法
            performProcessing: function() {
                // 实际执行的方法
            },
            process: function() {
                clearTimeout(timeoutId);
                var that = this;
                this.timeoutId = setTimeout(function() {
                    that.performProcessing();
                }, 100);
            }
    }
    // 尝试开始执行
    processor.process();
    
  • 简化模式

    function throttle(method, context) {
        clearTimeout(method.tId);
        method.tId = setTimeout(function() {
            method.call(context);
        }, 100);
    }
    

作用域安全的构造函数

    function Polygon(sides) {
        if (this instanceof Polygon) {
            this.sides = sides;
            this.getArea = function() {
                return 0;
            }
        } else {
            return new Polygon(sides);
        }
    }

    function Rectangle(width, height) {
        Polygon.call(this, 2);
        this.width = width;
        this.height = height;
        this.getArea = function() {
            return this.width * this.height;
        }
    }
    // 继承 
    Rectangle.prototype = new Polygon();
    var rect = new Rectangle(5, 10);
    rect.getArea();  // -> 50
    rect.sides; // -> 2

使用原型来实现数据备份

原理是利用原型对象来储存实例对象的所有可枚举的属性 P.prototype[i] = this[i];

    function P(x) {
        this.x = x;
    }
    P.prototype.backUp = function() {
        for (var i in this) {
            P.prototype[i] = this[i];
        }
    };

    var p1 = new P(1);
    p1.backUp();
    p1.x; // -> 1
    p1.x = 10;
    p1.x; // -> 10
    p1 = P.prototype;
    p1.x; // -> 1

批量修改原型对象

这样如果想要修改所有复制到实例的x值 只需要修改原型对象中的值 就可以了

function F(x) {
    this.x = x;
}
var a = [];

function Temp() {}
Temp.prototype = new F(10);
for (var i = 0; i < 10; i++) {
    a[i] = new Temp();
}

函数的引用和调用

函数的调用能够改变函数的执行作用域

var o = {
    name: "object o",
    f: function() {
        return this;
    }
};
o.o1 = {
    name: "object o1",
    me: o.f // 引用了o.f的方法
}
var who = o.o1.me();
who.name; // -> "object o1"
o.o2 = {
    name: "object o2",
    // 改变了当前的执行作用域
    me: o.f() // 调用了o.f的方法
}
var who = o.o2.me;
who.name; // -> "object o"

快速打印一个五分制的评分情况

function getRating(rating) {
    if(rating > 5 || rating < 0) {
        throw new Error('数字不在范围内");
    } else {
        return "★★★★★☆☆☆☆☆".slice(5 - rating, 10 - rating);
    }
}
getRating(3);    // -> '★★★☆☆'

输出n个”abc”拼接成的字符串

var str = new Array(n + 1).join("abc");

jQuery 处理文档加载

    jQuery.ready.promise = function(obj) {
        if (!readyList) {
            readyList = jQuery.Deferred();
            if (document.radyState === "complete") {
                setTimeout(jQuery.ready);
            } else {
                document.addEventListener("DOMContentLoaded", completed, false);
                window.addEventListener("load", completed, false);
            }
        }
        return readyList.promise(obj);
    };

jQuery中执行noConflict函数的理解

1. 首先在<head></head>中可以插入脚本,比如是prototype.js和jQuery.js库
2. 在导入jQuery.js的时候,将prototype.js中的$进行保存, var _$ = window.$;
3. jQuery.js完全导入后,此时的window.$已经被替换成了jQuery中$
4. 当执行noConflict函数, 此时的window.$ === jQuery 成立,系统会将window.$ 替换成之前保存_$, 即prototype中的$
5. 此时即完成了jQuery让出$控制权的功能
6. 应该注意在加载jQuery之前已经存在一个$命名空间的的库,否则 var _$ = window.$就没有意义了

使用Cookie存储长信息

  • 读取所用cookie信息,包括子cookie信息
  • 返回: 对象 存储cookie值
  • bug: 测试数据无法中的过期时间无法加入到o对象中去

    function getSubCookie() {
        var a = document.cookie.split(";");
        console.log(a.length);
        var o = {};
        for (var i = 0; i < a.length; i++) {
    
        // 消除a[i]字符串中的头部尾部字符串 类似于trim()函数
        a[i] && (a[i] = a[i].replace(/^\s+|\s+$/, ""));
        var b = a[i].split("=");
        var c = b[1];
        c && (c = c.replace(/^\s+|\s+$/, ""));
        c = unescape(c); // 解码cookie值
        if (!/\,/.test(c)) { // 判断是否包含"," 如果没有 则表示只包含一个子cookie信息
            o[b[0]] = b[1];
        } else {
            var d = c.split(",");
            for (var j = 0; j < d.length; j++) {
                var e = d[j].split(":");
                o[e[0]] = e[1]; // 把子cookie信息写入返回对象中去
            }
        }
    }
    return o;
    }
    
测试数据
// 定义expires有效期
// 实验数据 "user=escape(a); expires=d"
var d = new Date();
d.setMonth(d.getMonth() + 1);
d = d.toUTCString();
var a = "name:a, age:20, addr:beijing";
var c = "user=" + escape(a); // escape() 编码
c = c + ";" + "expires=" + escape(d);
document.cookie = c; // 写入cookie信息
if (navigator.cookieEnabled) {
    var o = getSubCookie();
    console.log(o);
}

封装cookie应用接口

  • 传入一个参数时, 表示读取指定的cookie的值
  • 传入两个参数时, 表示写入cookie信息, 第一个参数表示名称,第二个参数表示值
  • 第三个参数传递选项信息,对象

    function cookie(name, value, options) {
        if (typeof value != "undefined") { // 如果第二个参数存在
            options = options || {};
            if (value === null) {
                options.expires = -1; // 设置失效时间
            }
            var expires = "";
            if (options.expires && (typeof options.expires == "number" || options.expires.toUTCString)) {
                var date;
                if (typeof options.expires == "number") {
                    date = new Date();
                    date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
                } else {
                    date = options.expires;
                }
                expires = "; + expires=" + date.toUTCString();
            }
            var path = options.path ? "; path=" + options.path : ""; // 设置路径
            var domain = options.domain ? "; domain=" + options.domain : ""; // 设置域
            var secure = options.secure ? "; secure=" + options.secure : ""; //  设置安全措施,为ture则直接设置
            document.cookie = [name, "=", encodeURIComponent(value), expires, path, domain, secure].join("");
        } else { // 如果第二个参数不存在,则表示读取指定cookie信息
            var cookieValue = null;
            if (document.cookie && document.cookie != " ") {
                var cookie = document.cookie.split(";");
                for (var i = 0; i < cookie.length; i++) {
                    var cookie[i] = (cookie[i] || " ").replace(/^\s+|\s+$/, "");
                    if (cookie[i].slice(0, name.length + 1) == (name + "=")) {
                        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                        break;
                    }
                }
            }
            return cookieValue; //  返回查找的cookie值
        }
    }
    

条件预加载

// 兼容事件监听函数
function addHeadler(target, eventType, handler) {
    if (target.addEventListener) { // DOM2 Events
        addHeadler = function(target, eventType, handler) {
            target.addEventListener(eventType, handler, false);
        };
    } else { // IE
        addHeadler = function(target, eventType, handler) {
            target.attachEvent("on" + eventType, handler);
        };
    }
    addHeadler(target, eventType, handler);
}

// 条件预加载
var addHeadler = document.body.addEventListener ? function(target, eventType, handler) {
    target.addEventListener(eventType, handler, false);
} : function(target, eventType, handler) {
    target.attachEvent("on" + eventType, handler);
};

随机加载函数

// Math.random() * Math.random()  随机数接近于0而疏远于1
function updateRandom() {
    var p = Math.random(),
        n = Math.random() / 4;
    if (p < 0.01) {
        return 0 + n; // [0, 0.25)
    } else if (p < 0.04) {
        return 0.25 +  n; // [0.25, 0.5)
    } else if (p < 0.1) {
        return 0.5 + n; // [0.5, 0.75)
    } else {
        return 0.75 + n; // [0.75, 1)
    }
}

var objects = ["登山包", "旅行箱", "移动电源", "不中奖"];
var object = [];
var num = [0, 0, 0, 0];
for (var i = 0; i < 1000; i++) {
    var randomIndex = Math.floor(objects.length * updateRandom());
    object[i] = objects[randomIndex];
    if (object[i] == "登山包") {
        num[0]++;
    } else if (object[i] == "旅行箱") {
        num[1]++;
    } else if (object[i] == "移动电源") {
        num[2]++;
    } else {
        num[3]++;
    }
}
num; // 输出测试数据

生成工厂函数

function randomInProbability(weights) {
    if (arguments.length > 1) {
        weights = [].slice.call(arguments);
    }
    var total, current = 0,
        parts = [],
        i = 0,
        len = weights.length;
    total = weights.reduce ? weights.reduce(function(a, b)) {
        return a + b;
    }): eval(weights.join("+"));
for (; i < len; i++) {
    current += weights[i];
    parts.push("if(p<", current / total, "return", i / len, "+n");
}
return Function("var p = Math.random(), n = Math.random() / " + len + ";" + parts.join(""));
}

自定义事件

function EventTarget() {
    this.handlers = {};
}
EventTarget.prototype = {
    constructor: EventTarget,
    addHeadler: function(type, handler) {
        if (typeof this.handlers[type] == "undefined") {
            this.handlers[type] = [];
        }
        this.handlers[type].push(handler);
    },
    fire: function(event) {
        if (!event.target) {
            event.target = this;
        }
        if (this.handlers[event.type] instanceof Array) {
            var handlers = this.handlers[event.type];
            for (var i = 0; len = handlers.length; i < len; i++) {
                handlers[i](event);
            }
        }
    },
    removeHandler: function(type, handler) {
        if (this.handlers[type] instanceof Array) {
            var handlers = this.handlers[type];
            for (var i = 0, len = handlers.length; i < len; i++) {
                if (handlers[i] == handler) {
                    break;
                }
            }
            handlers.slice(i, 1);
        }
    }
};

function handlerMessage(event) {
    alert("Message received: " + event.message);
}
// 创建一个新对象
var target = new EventTarget();

// 添加一个事件处理程序
target.addHeadler("message", handlerMessage);

// 触发事件
target.fire({
    type: "message",
    message: "Hello world!"
});

// 删除事件处理程序
target.removeHandler("message", handlerMessage);

// 再次, 应没有处理程序
target.fire({
    type: "message",
    message: "Hello world!"
});

鼠标拖动功能

var drogDrop = function() {
    var dragging = null;

    function handlerEvent(event) {
        // 获取事件和目标
        event = EventUtil.getEvent(event);
        var target = EventUtil.getTarget(event);

        // 确定事件类型
        switch (event, type) {
            case 'mousedown':
                if (target.className.indexOf('draggable') >  -1) {
                    dragging = target;
                }
                break;
            case 'mousemove':
                if (dragging != null) {

                    // 指定位置
                    dragging.style.left = event.clientX + 'px';
                    dragging.style.top = event.clientY + 'px';
                }
                break;
            case 'mouseup':
                dragging = null;
                break;
        }
    }
    // 公共接口
    return {
        enable: function() {
            EventUtil.addHeadler(document, 'mousedown', handlerEvent);
            EventUtil.addHeadler(document, 'mousemove', handlerEvent);
            EventUtil.addHeadler(document, 'mouseup', handlerEvent);
        },
        disable: function() {
            EventUtil.removeHandler(document, 'mousedown', handlerEvent);
            EventUtil.removeHandler(document, 'mousemove', handlerEvent);
            EventUtil.removeHandler(document, 'mouseup', handlerEvent);
        }

    };
}();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值