1.安全类型检测(toString方式)
因为javascript的本身检测并不是很可靠,比如在safari4以前的版本里,对正则表达式用typeof的时候,返回的是"function",instanceof在存在多个全局作用局(存在iframe)的情况下必须要保证对象和构造函数是同一个全局作用域下。
var arr1={ a:1, b:2 } var arr2=[1,2]; function isArray(value){ //这样子检验可以避免和变量作用域的绑定 return Object.prototype.toString.call(value)=="[object Array]"; } isArray(arr1); //false isArray(arr2); //true
注意:1 对于ie的COM对象实现的任何函数
2.作用域安全的构造函数
构造函数之所以被称为构造函数就是因为我们在调用这个函数的时候用了new关键字,如果不用的话就会出错
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; } var person=Person("xiaosi",20,"web"); alert(window.name); //xiaosi alert(window.age); //20 alert(window.job); //web alert(person.name); //报错,person未定义 alert(person.age); alert(person.job);
在执行下面的的 alert(person.name);时候会报错,报错的原因就是因为Person没有使用new关键字,所以只是个普通函数,而普通函数的话person等于Person的返回值,而Person没有返回值,所以person值为undefined;而上面 alert(window.name);会有返回值的原因是因为没有用new关键字会导致Person的this指向window
改进的函数:
function Person(name,age,job){ if(this instanceof Person){ this.name=name; this.age=age; this.job=job; alert("设置对应的属性"); }else{ alert("直接返回一个对象"); return new Person(name,age,job); } } var person1=Person("xiaosi","20","web"); alert(window.name); alert(person1.name); var person2=new Person("xiaosi","20","web"); alert(person2.name);
这样的话,构造函数会进行检验,如果不是通过new 关键字构造对象将会返回带new 的构造函数,然后重新构造一次
,但是,这会导致实现继承的时候出现问题:
function Person(name,age,job){ if(this instanceof Person){ this.name=name; this.age=age; this.job=job; alert("设置对应的属性"); }else{ alert("直接返回一个对象"); return new Person(name,age,job); } } function Me(love){ Person.call(this,"xiaosi","20","web"); this.love=love; this.getArea=function(){ return this.love(); } } var me=new Me("cancan"); alert(me.name); //undefined alert(me.age); //undefined alert(Me.job); //undefined
像这里会导致子类无法继承到父类的属性,而原因就是因为在调用call的时候,父类用了安全模式,导致子类无法调用父类的构造函数,因为原型链上的对象构造函数不同(注意,instanceof 不是用来检测对象类型的,而是用来检测对象原型链上是否存在某一构造函数,虽然返回结果类似,但是由于实际上检测的是原型链,会导致作用域不同情况下返回错误结果)
解决办法:给子类对象的原型链上添加一个父类的对象(原型链不是指向构造函数的)
function Person(name,age,job){ if(this instanceof Person){ this.name=name; this.age=age; this.job=job; alert("设置对应的属性"); }else{ alert("直接返回一个对象"); return new Person(name,age,job); } } function Me(love){ Person.call(this,"xiaosi","20","web"); this.love=love; this.getArea=function(){ return this.love(); } } Me.prototype=new Person(); //给Me添加原型链指向Person()的一个实例对象 var me=new Me("cancan"); alert(me.name); //undefined alert(me.age); //undefined alert(Me.job); //undefined
3.惰性载入函数(提高执行效率)
我们在写函数的时候往往需要进行很多的if判断,但是实际上如果我们得到了一次页面环境的话用不用再次判断了,如果直接调用函数的话就会比执行if判断更快速
function createXHR(){ if(window.XMLHttpRequest){ alert("创建XMLHttpRequest对象"); return new XMLHttpRequest(); }else if(window.ActiveXObject) { alert("创建ActiveXObject对象"); return new ActiveXObject(); }else{ alert("不能创建对象"); } } var xhr= createXHR();
这上面的代码就说明了这个问题,需要判断浏览器支持情况再执行构造函数,但是用户的判断情况只需要一次就可以了,所以,改进:
function createXHR() { if (window.XMLHttpRequest) { alert("创建XMLHttpRequest对象"); createXHR = function() { return new XMLHttpRequest(); } } else if (window.ActiveXObject) { alert("创建ActiveXObject对象"); createXHR = function() { return new ActiveXObject(); } } else { alert("不能创建对象"); } } var xhr = createXHR();
这样改进之后,实际上在执行完一次判断之后createXHR函数内容就被改变了,然后就可以直接针对浏览器执行我们想要的代码了
另一方式:
var createXHR = (function() { if (window.XMLHttpRequest) { alert("创建XMLHttpRequest对象"); return function() { return new XMLHttpRequest(); } } else if (window.ActiveXObject) { alert("创建ActiveXObject对象"); return function() { return new ActiveXObject(); } } else { alert("不能创建对象"); } })();
也是一样的在判断完成之后返回我们需要的函数