JavaScript高级程序设计学习笔记js高级技巧
2023-06-13 09:14:30 时间
第十八章高级技巧
1.高级函数
1.1作用域安全的构造函数
①直接调用构造函数而不适用new操作符时,由于this对象的晚绑定,它将映射在全局对象window上,导致对象属性错误增加到window。
复制代码代码如下:
1.高级函数
1.1作用域安全的构造函数
①直接调用构造函数而不适用new操作符时,由于this对象的晚绑定,它将映射在全局对象window上,导致对象属性错误增加到window。
functionPerson(name,age,job){
this.name=name;
this.age=age;
this.job=job;
}
Varperson=Person("Jay",29,"singer");//属性增加到window对象上。
②作用域安全构造函数
functionPerson(name,age,job){
if(thisinstanceofPerson){
this.name=name;
this.age=age;
}else{
returnnewPerson(name,age);
}
}
③上述作用域安全的构造函数,如果使用构造函数窃取模式的继承且不使用原型链,那么这个继承很可能被破坏。
□如果构造函数窃取结合使用原型链或者寄生式组合则可以解决这个问题。
functionPolygon(side){
if(thisinstanceofPolygon){
this.sides=sides;
this.getArea=function{return0;};
}else{
returnnewPolygon(sides);
}
}
functionRectangle(width,height){
Polygon.call(this,2);
this.width=width;
this.height=height;
this.getArea=function(){
returnthis.width*this.height;
};
}
Rectangle.prototype=newPolygon();
varrect=newRectangle(5,10);
alert(rect.sides);//2
1.2惰性载入函数
①惰性载入表示函数执行的分支仅会发生一次:既第一次调用的时候。在第一次调用的过程中,该函数会被覆盖为另一个按合适方式执行的函数,这样任何对原函数的调用都不用再经过执行的分支了。
■优点:
□要执行的适当代码只有当实际调用函数时才进行。
□尽管第一次调用该函数会因额外的第二个函数调用而稍微慢点,但后续的调用都会很快,因避免了多重条件。
functioncreateXHR(){
if(typeofXMLHttpRequest!="undefined"){
createXHR=function(){
returnnewXMLHttpRequest();
};
}elseif(typeofActiveXObject!="undefined"){
createXHR=function(){
if(typeofarguments.callee.activeXString!="string"){
varversions=["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"];
for(vaiI=0,len=versions.length;I<len;i++){
try{
Varxhr=newActiveXObject(version[i]);
Arguments.callee.activeXString=version[i];
Returnxhr;
}catch(ex){
//skip
}
}
}
returnnewActiveXObject(arguments.callee.activeXString);
};
}else{
createXHR=function(){
thrownewError("NoXHRObjectavailable.");
};
}
returncreateXHR();
}
1.3函数绑定
①函数绑定要创建一个函数,可以在特定环境中以指定参数调用另一个函数。
②一个简单的bind()函数接受一个函数和一个环境,并返回一个在给定环境中调用给定函数的函数,并且将所有参数原封不动传递过去。
functionbind(fn,context){
returnfunction(){
returnfn.apply(context,arguments);
};
}
③被绑定函数与普通函数相比有更多的开销——它们需要更多内存,同时也因为多重函数调用而稍微慢一点——所以最好只在必要时使用。
1.4函数柯里化
定义:用于创建已经设置好了一个或多个参数的函数。函数柯里化的基本方法和函数绑定是一样的:使用一个闭包返回一个函数。两者的区别在于,当函数被调用时,返回函数还需要设置一些传入的参数。
functionbind(fn,context){
varargs=Array.prototype.slice.call(arguments,2);
returnfunction(){
varinnerArgs=Array.prototype.slice.call(arguments);
varfinalArgs=args.concat(innerArgs);
returnfn.apply(context,finalArgs);
};
}
2.高级定时器
①JavaScript是单线程程序,定时器是在间隔时间后将代码添加到列队。
②执行完一套代码后,JavaScript进程返回一段很短的时间,这样页面上的其他处理就可以进行了。
2.1重复的定时器
①setInterval()仅当没有该定时器的任何其他代码实例时,才将定时器代码添加到队列中。
□某些间隔会被跳过。
□多个定时器代码执行之间的间隔可能会比预期小。
②避免setInterval()的两个缺点,使用链式setTimeout()调用:
setTimeout(function(){
//处理
if(condition){
setTimeout(arguments.callee,interval);
}
},interval);
2.2YieldingProcesses
①JavaScript长时间运行脚本制约:如代码运行超过特定的时间或特定的语句数量就不会让它继续执行。
②当某个函数要花200ms以上的事件完成,最好分割为一系列可以使用定时器的小任务。
③数组分块技术:为要处理的项目创建一个队列,然后使用定时器取出下一个要处理的项目进行处理,接着再设置另一个定时器。
functionchunk(array,process,context){
setTimeout(function(){
varitem=array.shift();
process.call(context,item);
if(array.length>0){
setTimeout(arguments.callee,100);
}
}
}
2.3函数节流
①DOM操作比起非DOM交互需要更多内存和CPU时间。连续尝试进行过多的DOM相关操作可能会导致浏览器挂起,有时甚至崩溃。
②函数节流思想:某些代码不可以在没有间断的情况连续重复执行。
□示例
varprocessor={
timeoutId:null,
//实际进行处理的方法
performProcessing:function(){
//实际执行的方法
},
//初始处理调用的方法
process:function(){
clearTimeout(this.timeoutId);
varthat=this;
this.timeoutId=setTimeout(function(){
that.performProcessing();
},100);
}
};
//尝试开始执行
Processor.process();
□简化模式
functionthrottle(method,context){
clearTimeout(mehtod.tId);
mehtod.tId=setTimeout(function(){
method.call(context);
},100);
}
3.自定义事件
①事件是一种叫做观察者的设计模式,这是一种创建松散耦合代码的技术。
□对象可以发布事件,用来表示该对象声明周期中某个有趣的时刻到了。
□其他对象可以观察该对象,等待有趣的时刻到来并通过运行代码来响应。
②观察者模式由两类对象组成:主体和观察者。
□主体负责发布事件,同时观察者通过订阅这些事件来观察主体。
□主体并不知道观察者的任何事情,它可以独立自存在并正常运作即使观察者不在。
③自定义事件:创建一个管理事件的对象,让其他对象监听那些事件。
functionEventTarget(){
this.handlers={};
}
EventTarget.prototype={
constructor:EventTarget,
addHandler:function(type,handler){
if(typeofthis.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]instanceofArray){
varhandlers=this.handlers[event.type];
for(vari=0,len=handlers.length;i<len;i++){
handlers[i](event);
}
}
},
removeHandler:function(type,handler){
if(this.handlers[type]instanceofArray){
varhandlers=this.handlers[type];
for(vari=0,len=handlers.length;i<len;i++){
if(handlers[i]===handler){
break;
}
}
Handlers.splice(i,1);
}
};
④使用EventTarget类型的自定义事件可以如下使用:
functionhandleMessage(event){
alert("messagereceived:"+event.message);
}
//创建一个新对象
vartarget=newEventTarget();
//添加一个事件处理程序
target.addHandler("message",handleMessage);
//触发事件
target.fire({type:"message",message:"helloworld!"});
//删除事件处理程序
target.removeHandler("message",handleMessage);
⑤使用实例
functionPerson(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});
};
functionhandleMessage(event){
alert(event.target.name+"says:"+event.message);
}
//创建新person
varperson=newPerson("Nicholas",29);
//添加一个事件处理程序
Person.addHandler("message",handleMessage);
//在该对象上调用1个方法,它触发消息事件
person.say("Hithere");
4.拖放
功能:①拖放②添加了自定义事件
varDragDrop=function(){
vardragdrop=newEventTarget();
vardragging=null;
vardiffX=0;
vardiffY=0;
functionhandleEvent(event){
//获取事件和对象
event=EventUtil.getEvent(event);
vartarget=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;
dragdorp.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:dargging,
x:event.clientX,
y:event.clientY
}
);
}
break;
case"mouseup":
dargdorp.fire(
{
type:"dragend",
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);
};
returndragdrop;
}();
相关文章
- 编写js程序实现n的阶乘_javascript矩阵算法
- JavaScript基本知识点——带你逐步解开JS的神秘面纱
- JS获取当前年份_js获取当前时间年月日
- javascript获取当前时间,按指定格式输出_js获取现在本地时间的代码
- JS设置定时器_js设置定时器
- 他来了!性能吊打 Node.js 和 Deno 的新一代 javaScript 运行时!
- 试图颠覆 JavaScript 生态?亲身试用新 JS 运行时 Bun 后,我觉得未来可期
- JS引擎(0):JavaScript引擎群雄演义—起底JavaScript引擎
- JavaScript连接MySQL数据库:深入解析(js链接mysql)
- 快速掌握JS操作MySQL数据库技巧(js操作mysql数据库)
- 使用JavaScript在Oracle中执行函数(js执行oracle函数)
- JavaScript探索之旅掌握Oracle和JS的完美融合(js与oracle)
- 将JavaScript文件存入Redis缓存(把js文件写入redis)
- 讨论javascript(一)工厂方式js面象对象的定义方法
- Javascript笔记一js以及json基础使用说明
- JavaScript学习笔记(一)js基本语法
- javascript快速排序函数代码
- javascript学习笔记(二)js一些基本概念
- JavaScript高级程序设计阅读笔记(十六)javascript检测浏览器和操作系统-detect.js
- javascript学习(一)构建自己的JS库
- javascript获得网页窗口实际大小的示例代码
- javascript验证身份证完全方法具体实现
- javascript利用apply和arguments复用方法
- javascript文件中引用依赖的js文件的方法