JavaScript基础——高级技巧

JavaScript中的函数非常强大,因为它们是第一类对象。使用闭包和函数环境切换,还可以有很多使用函数的强大方法。可以创建作用域安全的构造函数,确保在缺少new操作符时调用构造函数不会改变错误的环境对象。

  • 可以使用惰性载入函数,将任何代码分支推迟到第一次调用函数的时候。
  • 函数绑定可以让你创建始终在指定环境中运行的函数,同时函数柯里化可以让你创建已经填了某些参数的函数。
  • 将绑定和柯里化组合起来,就能够给你在任意环境中以任意参数执行任意函数的方法。
ECMAScript 5允许通过以下几种方式来创建防篡改对象。
  • 不可扩展的对象,不允许给对象添加新的属性或方法。
  • 密封的对象,也是不可扩展的对象,不允许删除已有的属性和方法。
  • 冻结的对象,也是密封的对象,不允许重写对象的成员。
JavaScript中可以使用setTimeout()和setInterval()如下创建定时器:
  • 定时器代码是放在一个等待区域,直到时间间隔到了之后,此时将代码添加到JavaScript的处理队列中,等待下一次JavaScript进程空闲时被执行。
  • 每次一段代码执行结束之后,都会有一小段空闲时间进行其他浏览器处理。
  • 这种行为意味着,可以使用定时器将长时间运行的脚本却分为一小块一小块可以在以后运行的代码段。这种做大有助于web应用对用户交互有更积极的响应。
JavaScript中经常以事件的形式应用观察者模式。虽然事件常常和DOM一起使用,但是你也可以通过实现自定义事件在自己的代码中应用。使用自定义事件有助于将不同部分的代码相互之间解耦,让维护更加容易,并减少引入错误的机会。
拖放对于桌面和web应用都是一个非常流行的用户界面范例,它能够让用户非常方便地以一种直观的方式重新排列或者配置东西。在JavaScript中可以使用鼠标事件和一些简单的计算来实现这种功能类型。将拖放行为和自定义事件结合起来可以创建一个可重复使用的框架,它能应用在各种不同的情况下。实际上,在HTML5规范中已经定义了拖放的方法。



    
    高级技巧
    








/**
 * 高级技巧
 */
function cl(x){
    console.log(x);
}
//跨浏览器的事件处理程序
var EventUtil={
    addHandler:function(element,type,handler){
        if(element.addEventListener){
            element.addEventListener(type,handler,false);
        }else if(element.attachEvent){
            element.attachEvent("on"+type,handler);
        }else{
            element["on"+type]=handler;
        }
    },
    removeHandler:function(element,type,handler){
        if(element.removeEventListener){
            element.removeEventListener(type,handler,false);
        }else if(element.detachEvent){
            element.detachEvent("on"+type,handler);
        }else{
            element["on"+type]=null;
        }
    }
};
/**
 * 22.1 高级函数
 */
//22.1.1 安全的类型检测
//检测是否为数组
function isArray(value){
    return Object.prototype.toString.call(value)=="[object Array]";
}
//检测是否为原生函数
function isFunction(value){
    return Object.prototype.toString.call(value)=="[object Function]";
}
//检测是否为正则表达式
function isRegExp(value){
    return Object.prototype.toString.call(value)=="[object RegExp]";
}
//检测是否为原生JSON对象
function isNativeJSON(value){
    return window.JSON && Object.prototype.toString.call(value)=="[object JSON]";
}

//22.1.2 作用域安全的构造函数
//作用域安全的构造函数在进行任何更改前,首先确认this对象是正确类型的实例。
//如果不是,那么会创建新的实例并返回。
function Person(name,age,job){
    if(this instanceof  Person){
        this.name=name;
        this.age=age;
        this.job=job;
    }else{
        return new Person(name,age,job);
    }
}
var person1=Person("Jason",24,"Software Engineer");
cl(window.name);//=>""
cl(person1.name);//=>"Jason"

//22.1.3 惰性载入函数
//惰性载入表示函数执行的分支仅会发生一次,有两种实现方式
//第一种就是在函数被调用时再处理函数;
//第二种是在声明函数时就指定适当的函数
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"];
                var i,len;
                for(i=0,len=versions.length;i5
cl(curriedAdd(3));//=>8
//创建柯里化函数的通用方式
function curry(fn){
    var args=Array.prototype.slice.call(arguments,1);
    return function(){
        var innerArgs=Array.prototype.slice.call(arguments);
        var finalArgs=args.concat(innerArgs);
        return fn.apply(null,finalArgs);
    };
}
function add1(num1,num2){
    return num1+num2;
}
var curriedAdd=curry(add1,5);
cl(curriedAdd(3));//=>8
var curriedAdd=curry(add1,5,12);
cl(curriedAdd());//=>17
//函数柯里化还常常作为函数绑定的一部分包含在其中,构造出更为复杂的bind()函数
function bind(fn,context){
    var args=Array.prototype.slice.call(arguments,2);
    return function(){
        var innerArgs=Array.prototype.slice.call(arguments);
        var finalArgs=args.concat(innerArgs);
        return fn.apply(context,finalArgs);
    };
}
var handler={
    message:"Event handled",
    handleClick:function(name,event){
        alert(this.message+":"+name+":"+event.type);
    }
}
var btn3=document.getElementById("my-btn3");
EventUtil.addHandler(btn3,"click",bind(handler.handleClick,handler,"my-btn3"));
//ECMAScript5的bind()方法也实现函数柯里化。
var btn4=document.getElementById("my-btn4");
EventUtil.addHandler(btn4,"click",handler.handleClick.bind(handler,"my-btn4"));


/**
 * 22.2 防篡改对象
 */
//22.2.1 不可扩展对象
var person1={name:"Jason"};
//阻止给对象添加属性和方法
Object.preventExtensions(person1);
person1.age=29;
cl(person1.age);//=>undefined
//确定对象是否可以扩展
cl(Object.isExtensible(person1));//=>false

//22.2.2 密封的对象
//Object.seal()方法,用来密封对象,即不能添加属性,也不能删除既有属性,不过可以修改属性值
var person2={name:"Jason"};
Object.seal(person2);
person2.age=29;
cl(person2.age);//=>undefined
delete person2.name;
cl(person2.name);//=>"Jason"
//检测对象是否被密封
cl(person2.isSealed(person2));//=>true

//22.2.3 冻结的对象
//冻结的对象既不可扩展,又是密封的,而且对数据属性的可写[[writable]]特性会被设置为false
var person3={name:"Jason"};
Object.freeze(person3);
person3.age=29;
cl(person3.age);//=>undefined
delete person.name;
cl(person3.name);//=>"Jason"
person3.name="Greg";
cl(person3.name);//=>"Jason"
//检测对象是否被冻结
cl(Object.isFrozen(person3));

/**
 * 22.3 高级定时器
 */
//22.3.1 重复的计时器
setTimeout(function(){
    var div=document.getElementById("myDiv");
    var left=parseInt(div.style.left)+5;
    div.style.left=left+"px";
    if(left<200){
        setTimeout(arguments.callee,50);
    }
},50);

//22.3.2 Yielding Processes
//数组分块的技术 定义一个chunk()方法
//接受三个参数:要处理的项目的数组,用于处理项目的函数,以及可选的运行该函数的环境
function chunk(array,process,context){
    setTimeout(function(){
        var item=array.shift();
        process.call(context,item);
        if(array.length>0){
            setTimeout(arguments.callee,100);
        }
    },100);
}
var data=[12,123,1234,453,23,23,5,4123,45,346,5643,2234,345,342];
function printValue(item){
    var div2=document.getElementById("myDiv2");
    div2.innerHTML+=item+"
"; } chunk(data.concat(),printValue); //22.3.3 函数节流 var processor={ timeoutId:null, //实际进行处理的方法 performProcessing:function(){ //实际执行的代码 }, //初始处理调用的方法 process:function(){ clearTimeout(this.timeoutId); var that=this; this.timeoutId=setTimeout(function(){ that.performProcessing(); },100); } }; //尝试开始执行 processor.process(); //可用throttle()函数来简化 function throttle(method,context){ clearTimeout(method.tId); method.tId=setTimeout(function(){ method.call(context); },100); } function resizeDiv(){ var div2=document.getElementById("myDiv2"); div2.style.height=div2.offsetHeight+"px"; } window.οnresize=function(){ throttle(resizeDiv()); } /** *22.4 自定义事件 */ //观察者模式:主体和观察者 //自定义事件:创建一个管理事件的对象,让其他对象监听那些事件。 function EventTarget(){ //用于储存事件处理程序 this.handlers={}; } EventTarget.prototype={ constructor:EventTarget, //用于注册给定类型事件的事件处理程序 addHandler: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



你可能感兴趣的:(javascript)