`
xieyaxiong
  • 浏览: 41130 次
  • 性别: 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的高级技巧,帮助开发者提升编程效率和代码质量。 1. 类型检测: 在JavaScript中,typeof操作符可以检测变量的基本类型,但无法区分对象类型的差异,如数组和对象。而instanceof则用于检查...

    JavaScript高级编程 pdf

    "JavaScript高级编程"这本书深入探讨了这门语言的高级特性和最佳实践,旨在帮助开发者提升技能水平,实现更高效、更可靠的代码编写。以下是该书可能涵盖的一些关键知识点: 1. **基础语法**:包括变量、数据类型...

    Javascript 高级程序设计(第3版)超清中文PDF

    《JavaScript高级程序设计》(第3版)是一本深入探讨该语言精髓的权威书籍,它为读者提供了全面且深入的JavaScript知识,包括语言核心、DOM操作、BOM处理、事件处理以及面向对象编程等多个方面。 在书中,作者详细...

    JavaScript 高级程序设计(第3版)【附源代码】

    《JavaScript高级程序设计(第3版)》是JavaScript学习者必备的经典教材,它深入讲解了JavaScript的核心概念、语法以及高级特性。这本书由资深JavaScript专家Nicholas C. Zakas撰写,为读者提供了全面且深入的...

    JavaScript.实用教程

    JavaScript高级技巧 - **异步编程**:学习如何使用回调函数、Promise和async/await处理异步操作。 - **模块化开发**:了解ES6模块和其他模块系统(如CommonJS)的使用。 - **框架与库**:探索流行的JavaScript框架...

    javascript高级代码例子

    "JavaScript高级代码例子"这个主题涵盖了JavaScript的高级特性和实践应用,旨在帮助开发者深入理解和运用这些高级技术。以下是对这些高级知识点的详细阐述: 1. **闭包(Closures)**:闭包是JavaScript中的一个...

    javascript高级教程.pdf

    《JavaScript高级教程》这本书深入探讨了这一动态语言的核心概念和技术,旨在帮助开发者提升技能,掌握JavaScript的高级用法。 首先,JavaScript是一种解释型的、基于原型的、动态类型的脚本语言。这意味着它不需要...

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

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

    javascript参考教程javascript高级教程javascript权威指南(第四版)

    在阅读这些文档的同时,配合《JavaScript+5.CHM》和《Javascript高级教程.CHM》这两份CHM格式的电子书,可以更直观地查找和学习特定知识点。CHM文件是Microsoft的帮助文档格式,包含了丰富的索引和搜索功能,便于...

    javascript高级编程技术

    学习JavaScript高级编程技术,首先需要理解脚本语言的概念。脚本语言是相对于编译型语言而言的,它们通常不需要预编译,而是直接由解释器执行。JavaScript就是这样的脚本语言,它在网页加载时被解释执行,可以实时...

    javascript高级编程JavaScript.pdf

    JavaScript,作为一种广泛应用于Web开发的脚本语言,其在实际应用中常常会遇到命名冲突的问题。特别是在大型项目中,...在实际开发中,应根据项目规模和团队协作的需求,灵活运用这些技巧来构建清晰、健壮的代码结构。

    JavaScript高级

    "JavaScript高级"这一主题深入探讨了这门语言的核心概念、高级特性以及最佳实践,旨在帮助那些已经掌握JavaScript基础的开发者进一步提升技能水平。下面将详细阐述JavaScript高级知识中的多个重要方面。 1. **原型...

    javascript高级编程PPT.zip

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

    javascript书藉大全

    理解闭包和立即调用的函数表达式(IIFE)也是JavaScript高级技巧的一部分。 4. **事件和DOM操作**:JavaScript与HTML文档对象模型(DOM)交互,可以改变网页内容、响应用户操作。事件监听器、事件冒泡和事件委托等...

    JavaScript小技巧全集 JavaScript教程 JavaScript源代码集

    总的来说,这个“JavaScript小技巧全集”涵盖了从基础到进阶的JavaScript知识,包括但不限于语法、DOM操作、事件处理、动画效果和高级技巧。无论你是初学者还是经验丰富的开发者,都可以从中受益,提升自己的...

    JavaScript高级程序设计第三版中文

    《JavaScript高级程序设计》是学习这一语言的经典教材,现在已经更新到第三版,并提供了完整的中文翻译,对于国内开发者来说,无疑是一份宝贵的资源。这本书深入浅出地讲解了JavaScript的核心概念和高级特性,帮助...

Global site tag (gtag.js) - Google Analytics