1.安全的类型检测
-----(1) 内置的JS类型检测机制并不是完全可靠的。
typeof有时会导致检测的数据类型不是可靠的结果。
instanceof在存在多个全局作用域的情况下无法得到准确的结果。
eg: var isArray = value instanceof Array;
返回TRUE的前提是 value是一个数组,并且该变量要和Array构造函数在同一个全局作用域中;不然若是value在其他的frame框架中定义的数组,上述代码就会返回false。
-----(2) 检测对象是原生对象还是开发人员自定义对象时也会有不可靠情况发生。
可以利用Object原生的toString方法。
如:Object.prototype.toString.call(value)==’[object Array]’
还可以利用该方法判断某个值是不是原生函数或者正则表达式;
Object.prototype.toString.call(value) ==’[object Function]’
Object.prototype.toString.call(value) ==’[object RegExp]’
但是,该方法不能检测非原生构造函数的构造函数名。所以如果用它检测自定义的构造函数会返回[object Object]
2.作用域安全的构造函数
在自定义构造函数中会有用到this关键字;在创建实例时,会用到new关键字,new的出现使得构造函数内部的this会指向新创建的实例对象。
var person = new Person();
但是如果没有用new调用构造函数会是什么情况呢?
如:var person = Person()
上述代码告诉我们,直接调用Person()构造函数也是可以的,但是this会隐射到window上,所以用window.属性名会打印出对的值,用person变量则会报错。如下:
原因:this对象的晚绑定,this被解析为window对象了。—全局对象意外的被设置属性导致不安全
解决办法:创建一个作用域安全的构造函数。
----if语句中加个判断:this instanceof 构造函数名
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);//this不是Person实例时则返回一个实例对象
}
}
var person1 = Person("XS", 20, "Software Engineer");
alert(window.name); //""
alert(person1.name); //"XS"
var person2 = new Person("Shelby", 4, "Ergonomist");
alert(person2.name); //"Shelby"
3. 惰性载入函数
惰性载入表示函数执行的分支仅会发生一次。代码中有if语句会比没有if语句执行的要慢,当有很多if语句时,如果if语句不必每次执行,那么代码的执行速度要快很多。如createXHR()函数。
实现方式:1.在函数被调用时再处理函数。
2. 在声明函数时指定恰当的函数。
4. 函数绑定
函数绑定的作用:将函数绑定到指定环境中,可以理解为改变this的指向。一般称为bind。
函数绑定常与回调函数和事件处理程序一起使用,以便在将函数作为变量传递的同时可以保留代码执行环境。
为什么需要函数绑定呢??
var handler= {
message: "event handled",
handleClick: function(event) {
alert(this.message);
}
};
var btn = document.getElementById("my-btn");
EventUtil.addHandler(btn,"click", handeler.handleClick); //这步使得函数的环境指向了DOM按钮
上述代码将handler.handleClick()方法分配给DOM事件处理程序,但是运行后发现结果显示为undefined。这是因为this对象指向的是btnDOM按钮,而不是handler对象(注意:在IE8中代码中的this指向的是window)。
----再来另外一个例子,如下:
var a=1;
var test = {
a: 2,
getA: function(){return this.a;}
};
test.getA(); //结果是2;
var reTest = test.getA; //将匿名函数赋值给了reTest变量
reTest(); //此时调用该函数的是window对象,this指向window,返回的是1
其实这种情况是可以利用闭包来解决的
//最后一句代码换成闭包函数来完成
EventUtil.addHandler(btn,"click", function(event) {
handeler.handleClick(event);
});
但是闭包过多的话会影响理解和调试,那么有没有更好的办法结决呢?----使用函数绑定,bind()方法实现~语法如下:
function bind(fn, context){
return function() {
return fn.apply(context, arguments);
}
}
bind()方法有两个参数,一个是需要传递保存执行环境的函数,一个是环境。如上。arguments指的是fn的参数,不是bind函数的参数
那么利用bind函数,第一个代码例子中的最后的一句代码可以更改为:
EventUtil.addHandler(btn,"click", bind(handeler.handleClick, handler);