博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JS学习笔记11_高级技巧
阅读量:4949 次
发布时间:2019-06-11

本文共 4016 字,大约阅读时间需要 13 分钟。

1.类型检测

typeof有时返回值不合理,比如RegExp对象返回object,测试代码:

var regex = /^what$/i;regex = new RegExp('^what$');alert(typeof regex);

instanceof在页面有多个frame时用不了,来自不同frame的对象instanceof返回false

可以用Object.prototype.toString.call(value) === ‘[object Array/Function...]’来做类型检查,也可以用来区分原生对象和自定义对象,例如:

[object JSON]//原生JSON对象[object Object]//自定义JSON对象

注意:IE中以COM对象形式实现的函数对象toString不会返回[object Function]

2.作用域安全的构造函数

用new操作符调用构造函数会给新创建的对象添加属性,而直接调用构造函数会给全局对象window添加属性

为了避免污染全局作用域,可以用如下构造函数:

/* 可能会污染全局作用域function Student(name){  this.name = name;}*///作用域安全的构造函数function Student(name){  if(this instanceof Student){    this.name = name;  }  else{    return new Student(name);  }}

上面的构造函数能够避免直接调用构造函数给全局对象意外添加属性,但用这种方式实现继承可能会出现问题,类型检查可能导致继承失败

3.惰性载入(避免重复分支检测)

  1. 在第一次执行分支检测时,覆盖原有函数,例如:

    function detect(){  if(...){    detect = function(){      //    }  }  else if(...){    detect = function(){      //    }  }  else...}
  2. 可以用匿名函数立即执行并返回匿名函数来实现惰性载入,例如:

    var detect = (function(){  if(...){    return function(){      //    }  }  else if(...){    return function(){      //    }  }  else...})();

第一种方式第一次调用时损失性能,以后调用不会损失性能;第二种方式在第一次调用时也不会损失性能,因为把时耗放到了第一次载入代码时

4.函数绑定(指定执行环境)

可以用下面的函数给函数指定执行环境并创造新函数:

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

可以方便地根据已有函数生成新函数,[IE9+]有原生的bind方法,例如var newFun = fun.bind(obj);

注意:函数绑定存在内存消耗多,执行慢的缺点

5.函数柯里化(也叫函数套用,允许指定一些参数)

创建柯里化函数的通用方式:

function curry(fun){  var args = Array.prototype.slice.call(arguments, 1);//去掉第一个参数fun,得到给定的参数值  return function(){    var innerArgs = Array.prototype.slice.call(arguments);//把内部arguments对象转换为数组(为了用concat方法)    var finalArgs = args.concat(innerArgs);//拼接参数列表    return fun.apply(null, finalArgs);//把拼接的参数列表传给fun  }}

或者增强bind方法实现柯里化:

function bind(fun, context){  var args = Array.prototype.slice.call(arguments, 2);//去掉前2个参数  return function(){    var innerArgs = Array.prototype.slice.call(arguments);//同curry    var finalArgs = args.concat(innerArgs);//同curry    return fun.apply(context, finalArgs);//指定执行环境和参数  }}

注意:柯里化和bind都存在额外开销,不要滥用

6.防篡改对象

  1. 不可扩展对象(不能添加新属性)

    var obj = {a : 1, b : 2};alert(Object.isExtensible(obj));//trueObject.preventExtensions(obj);//把obj设置为不可扩展alert(Object.isExtensible(obj));//falseobj.c = 3;alert(obj.c);//undefined

    注意:设置不可扩展操作无法撤销(改不回来),设置之后无法添加新属性,但可以修改/删除原有属性

  2. 密封对象(只能修改现有属性,无法删除或添加)

    var obj = {a : 1, b : 2};Object.seal(obj);//设置密封对象alert(Object.isSealed(obj));//trueobj.c = 3;alert(obj.c);//undefineddelete obj.a;//严格模式下报错alert(obj.a);//1
  3. 冻结对象(只读,访问器属性可写)

    var obj = {a : 1, b : 2};Object.freeze(obj);//设置密封对象alert(Object.isFrozen(obj));//trueobj.a = 3;alert(obj.a);//1

上面的实现都是ES5新增的部分,浏览器支持性未知,本机测试[IE8-]不支持,Chrome和FF支持

7.函数节流

把耗时的大任务分割成小块,用setTimeout控制执行

优点:提高了页面响应速度

缺点:逻辑连贯性没了,实现难度增大,而且不易实现事务控制,因为完整事务被拆开了

8.观察者模式

用自定义事件可以实现观察者模式:

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 handleMessage(event){  alert("Message received: " + event.message);}//创建新对象var target = new EventTarget();//添加事件处理器target.addHandler("message", handleMessage);//触发事件target.fire({ type: "message", message: "Hello world!"});//删除事件处理器target.removeHandler("message", handleMessage);//再次触发事件,应该没有事件处理器target.fire({ type: "message", message: "Hello world!"});

转载于:https://www.cnblogs.com/ayqy/p/4437106.html

你可能感兴趣的文章
ORACLE基础学习(2)-SQL语句
查看>>
Linux操纵系统下的Oracle数据库编程详解
查看>>
FullerScreen-Firefox 全屏表现扩展
查看>>
RedFlag 6.0 硬盘安置我解
查看>>
Android中AndroidManifest.xml警告:Should explicitly set android:allowBackup to true or false
查看>>
线程同步问题:生产者和消费者问题
查看>>
MySQL相关的中文编码错误解决【转】
查看>>
WPF中更改键盘默认指令小结
查看>>
机器学习中的一些软件安装
查看>>
jQuery.移除元素
查看>>
POJ分类
查看>>
php二分式查找
查看>>
linux 安装redis
查看>>
php unset()函数销毁变量但没有实现内存释放
查看>>
变量数据类型数据接收详解
查看>>
在Mac中像Windows一样查看Tomcat控制台信息
查看>>
KMP模板及总结
查看>>
Poj 1005
查看>>
Cursor的moveToFirst和moveToNext
查看>>
进程与线程的一个简单解释
查看>>