1.安全的原生类型检验
js的原生类型,可以用typeof判断,但有时会失效。比如typeof array返回的不是Array,而是Object;再比如老版本IE,会将function识别为Object。另外一个判断类型的是instanceof,它能够在对象的原型链中查找构造函数,但这种方法对于原生类型的判断也会出问题,因为某些原生构造函数用户是可以覆盖的,比如Array和JSON。请看下面的例子:- function Array(){
- this.type="new Array";
- this.length=7;
- }
- var a=new Array();
- alert(a.length);//7
- alert(typeof a);//object
- alert(a instanceof Array);//true
- var b=[1,2,3];
- alert(b.length);//3
- alert(b[1]);//2
- alert(typeof b);//object
- alert(b instanceof Array);//false
解决这一个问题的方法是利用toString。原生类型调用toString后会返回诸如"[object array]"的字符串,即便构造函数被恶意覆盖了,原生类型的toString方法是不会被覆盖的。
- function Array(){this.length=7;}
- var a=1;
- var b=true;
- var c="string";
- var d=[];
- var e=new Array();
- console.log(Object.prototype.toString.call(a));//[object Number]
- console.log(Object.prototype.toString.call(b));//[object Boolean]
- console.log(Object.prototype.toString.call(c));//[object String]
- console.log(Object.prototype.toString.call(d));//[object Array]
- console.log(Object.prototype.toString.call(e));//[object Object]
2.作用域安全的构造函数
在说对象创建的时候,我们给出了很多构造对象的方法,后来在说继承的时候,也使用了那些方法。但那些构造对象的方法都是不安全的。- function Person(name,age){
- this.name=name;
- this.age=age;
- }
- var p1=new Person("Brain",18);
- var p2=Person("Brain",18);
- alert(p1.name);//Brain
- alert(p2);//undefined
- alert(window.name);//Brain
- function Person(name,age){
- if(this instanceof Person){
- this.name=name;
- this.age=age;
- }else{
- return new Person(name,age);
- }
- }
- var p1=new Person("Brain",18);
- var p2=Person("TOM",18);
- alert(p1.name);//Brain
- alert(p2.name);//TOM
- alert(window.name);//""
3.懒惰载入函数
在写跨浏览器的函数时,难免要判断浏览器是否支持某功能。比如在IE8-的浏览器中绑定事件,是不能用addEventListener的,只能用attachEvent,然后就有了一下的函数:- function addListener(element,type,func){
- if(typeof element.addEventListener == "function"){
- console.log("addEventListener");
- element.addEventListener(type.toLocaleLowerCase(),func,false);
- }else{
- console.log("attachEvent");
- element.attachEvent("on"+type,func);
- }
- }
- addListener(document.getElementById("box1"),"Click",function(){});
- addListener(document.getElementById("box2"),"Click",function(){});
- /*控制台输出
- addEventListener
- addEventListener
- */
- function addListener(element,type,func){
- if(typeof element.addEventListener == "function"){
- console.log("addEventListener");
- element.addEventListener(type.toLocaleLowerCase(),func,false);
- addListener=function(e,t,f){
- console.log("override addEventListener");
- e.addEventListener(t.toLocaleLowerCase(),f);
- }
- }else{
- console.log("attachEvent");
- element.attachEvent("on"+type,func);
- addListener=function(e,t,f){
- console.log("override attachEvent");
- e.attachEvent("on"+t,f);
- }
- }
- }
- addListener(document.getElementById("box1"),"Click",function(){});
- addListener(document.getElementById("box2"),"Click",function(){});
- /*控制台输出
- addEventListener
- override addEventListener
- */
4.函数绑定
有些时候,我们希望某个函数的执行,一直呆在事先规定好的执行环境中,而且这个函数可以由事件触发,这种需求是很常见的。比如下面这个例子,通过对象名称调用对象的方法,结果如我们预期;但如果想通过按钮点击触发showMsg,alert出来的确实undefined,和我们的预期相左。- var handle={
- message:"handle mesasge",
- showMsg:function(event){
- alert(this.message);
- }
- }
- handle.showMsg();//handle message
- btn.addEventListener("click",handle.showMsg);
- btn.addEventListener("click",function(event){
- handle.showMsg(event);
- });
- function bind(func,content){
- return function(){
- return func.apply(content,argument);
- }
- }
- btn.addEventListener("click",bind(handle.showMsg,handle));