js高级技巧笔记(一)
- 安全的类型检测
Js的类型检测机制并非完全可靠,发生错误否定及错误肯定的情况也不少:
在safari 在对正则表达式应用typeof操作符时返回”function”,因此很难确定某个值到底是不是函数
Instanceof在包含多个框架的时候出现错误.
解决上述问题的办法都一样,在任何值上调用Object原生的toString方法,都会返回一个[object NativeConstructorName]格式的字符串,每个类内部都有一个[[Class]]属性,这个属性中就指定了上述字符串中的构造函数,例如
alert(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]”;
}
不过要注意,对应在ie中以COM对象形式实现的任何函数,isFunction()都将返回false
- 作用域安全
在js在自定义对象的构造函数的定义和用法是这样:
function Person(name,age,job){
this.name=name;
this.age=age;
this.job=job;
}
var person=new Person(“Nicholas”,29,”Software Engineer”);
上面的例子如果不用new,着this将会指向window对象,导致全局变量的污染,而且之前在一个大神的博客中提到,其实全局变量的性能消耗要比局部变量的性能消耗相对要大,他得出这个结论的论据是,js中有作用域(也叫执行环境)的概念,函数在查找里面的变量时候先会查找局部变量(即当前函数作用域)当找不到的时候在去找上一级的作用域以此类推直到window全局作用域,尽量声明局部变量可以避免这样逐级找的性能消耗.
解决上面可能污染全局变量的风险的方法如下:
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 Rnginneer”);
alert(window.name);//””
alert(person1.name);//”Nicholas”
var person2=new Person(“shelby”,34,”Ergonnmist”);
alert(person2.name);
这样就不会有污染全局变量的风险,当然这只是简单的封装,在jQuery源码中有更为复杂全面的封装,这里就不做说明,明年肯定要话半年的时间看jQuery源码,可能最多只能学到jQuery里面的皮毛.
- 惰性载入函数
因为浏览器之间的行为的差异,多数JavaScript代码都包含大量的if语句,将执行引导到正确的代码中,看看下面代码:
function createXHR(){
if(typeof XMLHttpRequest!=”undefined”){
return new XMLHttpRequest();
}else if(typeof ActiveXObject !=”undefined”){
if(typeof arguments.callee.activeXString!=”string”){
var versions=[“MSXML2.XMLHttp.6.0”,”MSXML2.XMLHttp.3.0”,”MSXL2.XMLHttp”],i,len;
for(i=0,len=versions.length;i<len;i++){
try{
new ActiveXObject(versions[i]);
Arguments.callee.activeXString=versions[i];
}catch(ex){
}
}
}
return new ActiveXObject(arguments.caller.activeXString);
}else{
throw new Error(“No XHR object available”)
}
}
每次调用这个方法的时候,它都要对浏览器所支持的能力仔细检查,首先检查内置的XHR,然后测试有没有基于ActiveX的XHR,最后如果都没有发现的话就抛出一个错误,每次调用该函数都是这样,所以如果if语句不必每次执行,俺么代码的可以运行的更快一些,可以用惰性载入来解决.
creatrXHR().
function createXHR(){
if(typeof XMLHttpRequest!=”undefined”){
createXHR=function(){
return new XMLHttpRequest();
}
}else if(typeof ActiveXObject !=”undefined”){
createXHR=function(){
if(typeof arguments.callee.activeXString !=”string”){
var versions=[“MSXNL2.XMLHttp.6.0”,”MSXNL2.XNLHttp.3.0”,”MSXML2.XNLHttp”],i,len;
for(i=0,len=versions.length;i<len;i++){
try{
new ActiveXObject(versions[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”);
}
}
return createXHR();
}
在这个懒性载入的creaXHR中,if语句的每一个分支都会为creaXHR变量赋值,有效覆盖了原有的函数,最后一步便是调用新赋值的函数
第二种实现懒性载入的方式是在声明函数时就指定适当的函数,这样,第一次调用函数时就不会损失性能了,而在代码首次加载时会损失一点性能.
var createXHR=(function(){
if(typeof XMLHttpRequest !=”undefined”){
return funciton(){
return new XMLHttpRequest();
}
}else if(typeof ActiveXObject !=”undefined”){
return funciton(){
if(typeof arguments.callee.activeXString !=”string”){
var versions=[“MSXML2.XMLHttp.6.0”,”MSXML2.XMLHttp.3.0”,”MSXML2.XMLHttp”],i,len;
for(i=0,len=versions.length;i<len;i++){
try{
new ActiveXObject(versions[i]);
arguments.callee.activeXString=versions[i];
break;
}catch(ex){
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
};
}else{
return function(){
throw new Brror(“No XHR object available”);
}
}
})()
- 函数绑定
函数绑定就是用this来保留函数的代码执行环境.例如:
var handler={
message:”Event handled”,
handleClick:funcion(event){
alert(this.message);
}
};
var btn=document.getElementById(“my-btn”);
EventUtil.addHandler(btn,”click”,function(event){
handler.handleClick(event);
});
这里用了闭包,因为单击事件的函数this会指向dom对象,加个闭包就保留函数原本的this对象.es5中有个原生的bind方法来绑定this.
- 函数柯里化
函数柯里化的基本方法和函数绑定是一样的:使用一个闭包返回一个函数.两者的区别在于,但函数被调用时,返回的函数还需要设置一些传入的参数.
柯里化通用方式如下:
function curry(fn){
var args=Array.prototype.slice.call(arguments,1);//注意这里是将非第一个的参数转换为数组,因为arguments本身不是数值只是用法很像数组
return function(){
var innerArgs=Array.prototype.slice.call(arguments);
var finalArgs=args.concat(innerArgs);//将参数合并
return fn.apply(null,finalArgs);
}
}
这只是简单的柯里化,下面是柯里化实际应用代码:
function bind(fn,context){
var args=Array.prototype.slice.call(arguments);
return function(){
var innerArgs=Array.prototype.slice.call(arguments);
var finalArgs=args.concat(innerArgs);
return fn.apply(context,finalArgs);
}
}
var handler={
message:”Event handled”,
bandleClick:function(name,event){
alert(this.message+”:”+name+”;”+event.type);
}
};
var btn=document.getElementById(“my-btn”);
EventUtil.addHandler(btn,”click”,bind(handler.handleClick,handler,”my-btn”));
Es5的bind方法也能实现函数的柯里化,只要在this的值之后再传入另一个参数即可.例如:
var handler={
message:”Event handled”,
handleClick:function(name,event){
alert(this.message+”:”+name+”:”+event.type);
}
};
var btn=doucument.getElementById(“my-btn”);
EventUtil.addHandler(btn,”click”,hander.handlerClick.bind(handler,”my-btn”));
另外柯里化不太适合在项目功能层使用,第一使用不当容易造成内存泄漏,第二功能层是业务功能实现层,这层在后期维护,系统优化改动是最大的,所以业务层必须要保证代码的可读性,代码注释齐全,复杂的函数回调尽量少用,而在基础封装层也就是通用基础功能封装层可以用这种代码,第一这层改动比较少,第二代码复杂,第三要保证用的人简单,这层一般是组长级别的来维护.
- 防篡改对象
1.不可扩展对象
Es5提供对改变属性的行为,使用Object.preventExtensions()方法可以让指定的对象不能添加属性.例如:
var person={name:”Nicholas”};
Object.preventExtensions(person);
person.age=29;
alert(person.age);//undefined
可以用Object.isExtensible()方法来判断对象是否可以扩展.例如:
var person={name:”Nicholas”};
alert(Object.isExtensible(person));//true
Object.preventExtensions(person);
alert(Object.isExtensible(person));//false
2.密封的对象
Es5可以通过Object.seal方法将对象设置为密封对象,不能添加也不能删除属性,例如:
var person={name:”Nicholas”};
Object.seal(person);
person.age=29;
alert(person.age);//undefined
delete person.name;
alert(person.name)//”Nicholas”
用Object.isSealed()方法可以确定对象是否被密封,例如:
var person={name:”Nicholas”};
alert(Object.isExtensible(person));//true
alert(Object.isSealed(person));//false
Object.seal(person);
alert(Object.isExtensible(person));//false
alert(Object.isSealed(person));//true
3.冻结的对象
Es5可以用object.freeze冻结对象
Object.isFrozen方法用于检测冻结对象
js高级技巧笔记(一)的更多相关文章
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- Vue.js学习笔记(2)vue-router
vue中vue-router的使用:
- js读书笔记
js读书笔记 基本类型的基本函数总结 1. Boolean() 数据类型 转换为true的值 转换为false的值 Boolean true false String 任何非空字符串 "&q ...
- React.js入门笔记
# React.js入门笔记 核心提示 这是本人学习react.js的第一篇入门笔记,估计也会是该系列涵盖内容最多的笔记,主要内容来自英文官方文档的快速上手部分和阮一峰博客教程.当然,还有我自己尝试的 ...
- JS 学习笔记--9---变量-作用域-内存相关
JS 中变量和其它语言中变量最大的区别就是,JS 是松散型语言,决定了它只是在某一个特定时间保存某一特定的值的一个名字而已.由于在定义变量的时候不需要显示规定必须保存某种类型的值,故变量的值以及保存的 ...
- node.js系列笔记之node.js初识《一》
node.js系列笔记之node.js初识<一> 一:环境说明 1.1 Linux系统CentOS 5.8 1.2 nodejs v0.10.15 1.3 nodejs源码下载地址 htt ...
- JS面向对象笔记二
菜单导航,<JS面向对象笔记一>, 参考书籍:阮一峰之<JavaScript标准参考教程> 一.构造函数和new命令 二.this关键字 三.构造函数和new命令 四.构造函 ...
- WebGL three.js学习笔记 使用粒子系统模拟时空隧道(虫洞)
WebGL three.js学习笔记 使用粒子系统模拟时空隧道 本例的运行结果如图: 时空隧道demo演示 Demo地址:https://nsytsqdtn.github.io/demo/sprite ...
- WebGL three.js学习笔记 法向量网格材质MeshNormalMaterial的介绍和创建360度全景天空盒的方法
WebGL学习----Three.js学习笔记(5) 点击查看demo演示 Demo地址:https://nsytsqdtn.github.io/demo/360/360 简单网格材质 MeshNor ...
随机推荐
- Jedis操作Redis数据库
添加Maven依赖: <dependencies> <!-- 单元测试 --> <dependency> <groupId>junit</grou ...
- 编写SASS的一些技巧
更好的为变量命名 变量是Sass中最简单的特性之一,但有时候也会使用不当.创建站点范围内有语义化的变量,是不可或缺的工作.如果命名不好,他会变得难以理解和重复使用. 这里有一些命名变量的小技巧,提供参 ...
- 通过ASP禁止指定IP和只允许指定IP访问网站的代码
过ASP禁止指定IP和只允许指定IP访问网站的代码,需要的朋友可以参考下. 一.禁止指定IP防问网站,并执行相应操作: 代码如下: <% Dim IP,IPString,VisitIP '设置I ...
- Dalvik字节码的类型,方法与字段表示方法
Dalvik字节码有着自己的类型,方法与字段表示方法,这些方法与Dalvik虚拟机指令集一起组成了一条条的Dalvik汇编代码. 1.类型 Dalvik字节码只有两种类型,基本类型与引用类型.Dalv ...
- select into 、 insert into select 、create table as select复制表
Insert是T-sql中常用语句,Insert INTO table(field1,field2,...) values(value1,value2,...)这种形式的在应用程序开发中必不可少.但 ...
- 申请Android Map 的API Key(v2)的最新申请方式(SHA1密钥)
申请Android Map 的API Key(v2)的最新申请方式(SHA1密钥)具体步骤如下: ...
- OC6_复合类的类存管理
// // Person.h // OC6_复合类的类存管理 // // Created by zhangxueming on 15/6/18. // Copyright (c) 2015年 zhan ...
- requirejs实验002. r.js合并文件. 初体验.
requirejs的官网上有介绍如何使用r.js合并,压缩文件的.http://requirejs.org/docs/optimization.html https://github.com/jrbu ...
- Ubuntu、Sql Server卸载心得
这几天真是搞得亏大了! 首先是卸载Ubuntu,直接在Windows下格式化那个盘了,这就出岔子了……然后越来越糟糕,最后弄得一个系统都没有了……然后重装系统…… 然后装VS和Sql Server,因 ...
- ubuntu 14.04 nagios4+ndoutils2.0+centreon2.5.4配置
ubuntu 14.04 nagios4+ndoutils2.0+centreon2.5.4(原创) 开发应用centreon是开源的IT监控软件,由法国人于2003年开发,最初名为Oreon,并于2 ...