`
xieyaxiong
  • 浏览: 39058 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

javascript 高级技巧

 
阅读更多

1:高级函数

 

 

1.1 作用域安全的构造函数

function Person(name,age,job){
	this.name=name;
	this.age=age;
	this.job=job;
}

var person=Person("Nicholas",29,"Software Engineer");
alert(window.name); //"Nicholas"
alert(window.age);  //29
alert(window.job);  //Software Engineer
/**
 *因为构造函数是作为普通函数调用的,忽略了new操作符。这个问题是由this对象的晚绑定造成的,在这里this被解析成了window对象。
 * window 的name属性是用于识别链接目标和框架的,所以这里对该属性的偶然覆盖可能会导致该页面上出现其他错误。
 * 这个问题的解决方法就是创建一个作用域安全的构造函数。 
 */
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("Nicholas",29,"Software Engineer");
alert(window.name); //""
alert(person1.name); //"Nicholas"

var person2=Person("Shelby",34,"Ergonomist");
alert(person2.name); //"Shelby";


/**
 *如果使用构造函数窃取模式的继承且不使用原型链,那么这个继承很可能被破坏。0 
 */
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;
	}
}
var rect=new Rectangle(5,10);
alert(rect.sides); //undefined


/**
 * 如果构造函数窃取结合使用原型链或者寄生组合则可以解决这个问题。 
 */
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);
alert(rect.sides); 

 

 

1.2:惰性载入函数

/**
 * 惰性载入函数 
 * 
 * 每次调用createXHR()的时候,它都要对浏览器所支持的能力仔细检查。首先检查内置的XHR,然后测试有没有基于ActiveX的XHR,
 * 最后如果都没有发现的话就抛出一个错误。每次调用 该函数都是这样,即使每次调用时分去的结果都不变。
 */
function createXHR(){
	if(typeof XMLHttpRequest !="undefined"){
		return new XMLHttpRequest();
	}else if(typeof ActiveXObject != "undefined"){
		if(typeof arguments.call.activeXString != "string"){
			var versions=["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"];
			
			for(var i=0,len=versions.length;i<len;i++){
				try{
					new ActiveXObject(version[i]);
					arguments.callee.activeXString=versions[i];
					break;
				}catch(ex){
					//跳过
				}
			}
		}
		
		return new ActiveXObject(arguments.callee.activeXString);
	}else{
		throw new Error("No XHR object available.");
	}
}


/**
 *解决方案就是称之为惰性载入的技巧。
 * 惰性载入表示函数执行的分支仅会发生1次:即函数第一次调用的时候。 在第一次调用 的过程中,
 * 该函数会被覆盖为另一个按合适方式执行的函数,这样任何对原函数的调用都不用再经过执行的分支了。 
 */

function createXHR() {
	if( typeof XMLHttpRequest != "undefined") {
		createXHR = function() {
			return new XMLHttpRequest();
		}
	} else if( typeof ActiveXObject != "undefined") {
		createXHR = function() {
			if( typeof arguments.call.activeXString != "string") {
				var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"];

				for(var i = 0, len = versions.length; i < len; i++) {
					try {
						new ActiveXObject(version[i]);
						arguments.callee.activeXString = versions[i];
						break;
					} catch(ex) {
						//跳过
					}
				}
			}

			return new ActiveXObject(arguments.callee.activeXString);
		}
	} else {
		createXHR=function(){
			throw new Error("No XHR object available.");
		}
	}
}

 

 

1.3:函数绑定

/**
 * 函数绑定
 * 
 * 函数绑定要创建一个函数,可以在特定环境中以指定参数调用另一个函数。该技巧常常和回调函数与事件处理程序一起使用。
 * 以将函数作为变量传递的同时保留代码执行环境。 
 */

/**
 * 执行事件时,显示的是undefined。这个问题在于没有保存handler.handleClick()的环境。 
 */
var handler={
	message:"Event handled",
	handleClick:function(event){
		alert(this.message);
	}
}

var btn=document.getElementById("myBtn");
EventUtil.addHandler(btn,"click",handler.handleClick);


/**
 * 使用一个闭包来修正这个问题 
 */
var handler={
	message:"Event handled",
	
	handleClick:function(event){
		alert(this.message);
	}
};

var btn=document.getElementById("myBtn");
EventUtil.addHandler(btn,"click",function(event){
	handler.handleClick(event);
})


/**
 *以上是特定于那段代码的解决方案,创建多个闭包可能会令代码变得难于理解和调试。
 * 因此,很多javascript库实现了一个可以将函数绑定到指定环境的函数。这个函数一般都叫bind().
 * 一个简单的bind()函数接受一个函数和一个环境,并返回一个在给定环境中调用 给定对象的函数,
 * 并且将所有参数原封不动传递过去。 
 */

/**
 *这个函数似乎简单,但其功能是非常强大的。在bind()中创建一个闭包,闭包使用apply()调用传入的函数,
 * 并给apply()传递context对象和参数。注意这里使用的arguments对象是内部函数的,而非bind() 的。
 */
function bind(fn,context){
	return function(){
		return fn.apply(context,arguments);
	}
}

var handler={
	message:"Event handled",
	
	handleClick:function(event){
		alert(this.message);
	}
}

var btn=document.getElementById("myBtn");
EventUtil.addHandler(btn,"click",bind(handler.handleClick,handler));

 

 

 

1.4:函数柯里化

/**
 * 函数柯里化
 * 
 * 与函数绑定紧密相关的主题是函数柯里化(function currying ),它且于创建已经设置好一个或多个参数的函数。
 * 函数柯里化的基本方法和函数绑定是一样的:使用一个闭包返回一个函数。
 * 两者的区别在于,当函数被调用时,返回的函数还需要设置一些传入的参数。
 */

function add(num1,num2){
	return num1+num2;
}
function curriedAdd(num2){
	return add(5,num2);
}
alert(add(2,3))//5
alert(curriedAdd(3))//8

/**
 *尽管从技术上来说curriedAdd()并非柯里化的函数,但它很好地展示了其概念。
 * 柯里化函数通常由以下步骤动态创建:调用另一个函数并为它传入要柯里化的函数和必要参数。 
 */
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 add(num1,num2){
	return num1+num2;
}
var curriedAdd=curry(add,5);
alert(curriedAdd(3));//8
var curriedAdd=curry(add,5,12);
alert(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 btn=document.getElementById("myBtn");
EventUtil.addHandler(btn,"click",bind(handler.handleClick,handler,"myBtn"));

 

 

 

2: 定时器

/**
 *定时器
 * 
 * 虽然人们对javascript的定时器存在普遍的误解,认为它们是线程,其实javaScript是运行于单线程的环境中的,
 * 而定 时器仅仅只是计划代码在未来的某个执行时间。 
 */

 

 

 

3:自定义事件

/**
 *  自定义事件
 * 
 * 自定义事件背后的概念是创建一个管理事件的对象,让其他对象监听那些事件。 
 */
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<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.splice(i,1);
		}
	}
}


function Person(name,age){
	EventTarget.call(this);
	this.name=name;
	this.age=age;
}
inheritPrototype(Person,EventTarget);
Person.prototype.say=function(message){
	this.fire({type:"message",message:message});
}

function handleMessage(event){
	alert(event.target.name+" say: "+event.message);
}

//创建新person
var person=new Person("Nicholas",29);

//添加一个事件处理程序
person.addHandler("message",handleMessage);

//在该对象上调用1个方法,它触发消息事件
persona.say("Hi there.");

 

 

 

 

4:拖放

 

/**
 *拖放 
 */
var DragDrop=function(){
	
	var dragging=null;
	var diffx=0;
	var diffy=0;
	
	function handleEvent(event){
		//获取事件和目标
		event=EventUtil.getEvent(event);
		var target=EventUtil.getTarget(event);
		
		//确定事件类型
		switch(event.type){
			case "mousedown":
				if(target.className.indexOf("draggable")>-1){
					dragging=target;
					diffX=event.clientX-target.offsetLeft;
					diffY=event.clientY-target.offsetTop;
				}
				break;
			
			case "mousemove":
				if(dragging!=null){
					
					//获取事件
					event=EventUtil.getEvent(event);
					
					//指定位置
					dragging.style.left=(event.clientX-diffX)+"px";
					dragging.style.top=(event.clientY-diffY)+"px";
				}
				break;
				
			case "mouseup":
			 	dragging=null;
			 	break;
		}
	}
	
	//公共接口
	return{
		enable:function(){
			EventUtil.addHandler(document,"mousedown",handleEvent);
			EventUtil.addHandler(document,"mousemove",handleEvent);
			EventUtil.addHandler(document,"mouseup",handleEvent);
		},
		
		disable:function(){
			EventUtil.removeHandler(document,"mousedown",handleEvent);
			EventUtil.removeHandler(document,"mousemove",handleEvent);
			EventUtil.removeHandler(document,"mouseup",handleEvent);
		}
		
	}
}();


/**
 * 上面拖放功能还不能真正应用起来,除非能知道什么时候手动开始了。从这点上看,前面的代码没有提供任何方法表示拖动开始、
 * 正在拖动或者已经结束。这时,可以使用自定义事件来指示这几个事件的发生,让应用的其他部分与拖动功能进行交互。 
 */

var DragDrop=function(){
	
	var dragdrop=new EventTarget();
	
	var dragging=null;
	var diffx=0;
	var diffy=0;
	
	function handleEvent(event){
		//获取事件和目标
		event=EventUtil.getEvent(event);
		var target=EventUtil.getTarget(event);
		
		//确定事件类型
		switch(event.type){
			case "mousedown":
				if(target.className.indexOf("draggable")>-1){
					dragging=target;
					diffX=event.clientX-target.offsetLeft;
					diffY=event.clientY-target.offsetTop;
					dragdrop.fire({type:"dragstart",target:dragging,x:event.clientX,y:event.clientY});
				}
				break;
			
			case "mousemove":
				if(dragging!=null){
					
					//获取事件
					event=EventUtil.getEvent(event);
					
					//指定位置
					dragging.style.left=(event.clientX-diffX)+"px";
					dragging.style.top=(event.clientY-diffY)+"px";
					dragdrop.fire({type:"drag",target:dragging,x:event.clientX,y:event.clientY});
				}
				break;
				
			case "mouseup":
				dragdrop.fire({type:"darged",target:dragging,x:event.clientX,y:event.clientY});
			 	dragging=null;
			 	break;
		}
	}
	
	//公共接口
	
	dragdrop.enable=function(){
			EventUtil.addHandler(document,"mousedown",handleEvent);
			EventUtil.addHandler(document,"mousemove",handleEvent);
			EventUtil.addHandler(document,"mouseup",handleEvent);
		},
		
	dragdrop.disable=function(){
			EventUtil.removeHandler(document,"mousedown",handleEvent);
			EventUtil.removeHandler(document,"mousemove",handleEvent);
			EventUtil.removeHandler(document,"mouseup",handleEvent);
		}
		
	return dragdrop;
}();

DragDrop.addHandler("dragstart",function(event){
	var status=document.getElementById("status");
	status.innerHTML="Started dragging "+event.target.id;
});

DragDrop.addHandler("drag",function(event){
	var status=document.getElementById("status");
	status.innerHTML+="<br/> Draged "+event.target.id+" to("+event.x+","+event.y+")";
})

DragDrop.addHandler("draged",function(event){
	var status=document.getElementById("status");
	status.innerHTML="<br/> Dropped "+event.target.id+" at("+event.x+","+event.y+")";
})

 

分享到:
评论

相关推荐

    javascript高级技巧的应用——示例

    javascript高级技巧的应用——示例

    Javascript高级技巧分享

    主要介绍了Javascript高级技巧,需要的朋友可以参考下

    Javascript 高级程序设计第3版(完整源代码书上每个例子都有)

    直到当前它对XML和Web服务的具体支持,内容主要涉及JavaScript的语言特点、JavaScript与浏览器的交互、更高级的JavaScript技巧,以及与在Web应用程序中部署JavaScript解决方案有关的问题,如错误处理、调试、安全性...

    javascript高级编程PPT.zip

    javascript高级编程的JavaScript开始讲起,直到当前它对XML和Web服务的具体支持,内容主要涉及JavaScript的语言特点、JavaScript与浏览器的交互、更高级的JavaScript技巧,以及与在Web应用程序中部署JavaScript解决...

    JavaScript高级应用与实践

    资源名称:Javascript高级应用与实践内容简介:本书的内容涵盖大量提升Javascript性能的一些技巧、鲜为人知的写法,以及Javascript在Web项目中某些智能的、经典的设计。本书在讲解过程中会有大量...

    JavaScript中常用的简洁高级技巧总结

    主要给大家总结介绍了关于JavaScript中常用的简洁高级技巧,文中通过示例代码介绍的非常详细,对大家的学习或者使用Javascript具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

    Android Web Game App高级编程 使用HTML5 CSS3 JavaScript

    只需要具备一些HTML和JavaScript的基础知识 就可以开启我们的Android Web Game App高级编程之旅 从一个空白的HTML网页开始 最后将收获多人在线游戏 有丰富多彩的图像 声音 动画等 开发必需的一些知识和技巧 即使你...

    JavaScript高级程序设计 学习笔记 js高级技巧

    第十八章 高级技巧 1.高级函数 1.1 作用域安全的构造函数 ①直接调用构造函数而不适用new操作符时,由于this对象的晚绑定,它将映射在全局对象window上,导致对象属性错误增加到window。 代码如下: function Person...

    Maintainable+JavaScript(编写可维护的JavaScript)

    Zakas是顶级的Web技术专家,也是《JavaScript高级程序设计》一书的作者。他曾是Yahoo!的首席前端开发工程师,在完成了从一名“独行侠”到“团队精英”的蜕变后,他站在前端工程师的角度提炼出众多的最佳编程实践,...

    JavaScript详解,第2版(JavaScript by Example,2nd Edition)

    JavaScript详解,第2版(JavaScript by Example,2nd Edition)。英文清晰PDF版。...书中采用了大量课堂实践示例,附以详尽的代码行解释和实际结果输出,将javascript 基础知识与高级技巧完美地展现出来。

    [精通JavaScript动态网页编程].王俊杰.扫描版

    本书结合JavaScript 1 5和Jscript 5 5 由浅入深 循序渐进地全面介绍了JavaScript知识体系及编程设计技巧 全书分4篇 共30章 内容涵盖了JavaScript语法 JavaScript核心内容 JavaScript高级以及JavaScript应用等内容 对...

    JavaScript 高级程序设计(第3版)

    本书从最早期Netscape浏览器中的JavaScript开始讲起,直到当前它对XML和Web服务的具体支持,内容主要涉及JavaScript的语言特点、JavaScript与浏览器的交互、更高级的JavaScript技巧,以及与在Web应用程序中部署...

    编写可维护的JavaScript

    Zakas是顶级的Web技术专家,也是《JavaScript高级程序设计》一书的作者。他曾是Yahoo!的首席前端开发工程师,在完成了从一名“独行侠”到“团队精英”的蜕变后,他站在前端工程师的角度提炼出众多的最佳编程实践,...

    javascript技巧

    资源源于网猴!很不错的一个javascript学习资源,里面介绍了cookie,图片映射等高级技巧。

    Javascript高级应用与实践

    js 使用人员掌握初级 ,向高级进阶的不错的教程,书中例举了大量运行耗时的js实例,并一一进行了优化。 书中也有不少js的操作技巧及一些鲜为人知的用法。 书中阐述了海量交易项目的js项目经验

    JavaScript Best Practices & Tricks

    JavaScript的一些高级技巧,以及最佳实践。

Global site tag (gtag.js) - Google Analytics