1. 安全的类型检测
在任何值上调用Object类型原生的toString()
方法,都会返回一个[Object NativeConstructorName]
格式的字符串。且每个类(我认为是引用类型)在内部都有一个[[class]]
属性,这个属性中就指定了上述字符串中构造函数名。
1 | function isArray(value){ |
1 | function is(type, obj) { |
注意: Object类型原生的toString()
方法只能检测原生构造函数的构造函数名。因此,开发人员定义的任何构造函数都返回[object Object]。
2. 作用域安全的构造函数
问题:构造函数当普通函数使用时,函数内的this对象会被绑定window对象(全局执行环境==全局作用域),从而可能会导致页面上出现错误,因此作用域不安全。
解决方法:首先确认this
对象是正确类型的实例
1 | function Person(name,age,job){ |
后遗症:使用作用域安全的构造函数,就锁定了可以调用构造函数的环境。也就是说其作用域只有自己的变量对象和全局变量对象,不能被其他函数借用。使用借用构造函数模式继承,那么这个继承可能被破坏。
1 | function Polygon(sides){ |
解释:由于Polygon作用域是安全的,this
对象不是Polygon的实例,所以会创建一个新Polygon对象。Rectangle构造函数中是this对象并没有得到增长,同时Polygon.call()
返回的值也没有用到,所以Recanglt实例中不会有sides属性。
解决后遗症方法:借用构造模式结合使用原型链 组合继承或者寄生组合式继承。
1 | function Polygon(sides){ |
解释: 第一次调用时,在Rectangle原型上添加了sides属性,第二次调用时,this
代表的rect实例的instanceof指向Polygon,所以Polygon.call()
会照原意执行。
3. 惰性载入函数
惰性载入: 表示函数执行的分支仅会发生一次。两种实现惰性载入的方式:一是在函数被调用时再处理函数,二是声明函数时就指定恰当的函数。
- 在函数被调用时再处理函数:在第一次调用的过程中,该函数会被覆盖为另一个按合适方式执行的函数,这样任何对原函数的调用都不用再经过执行的分支了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30function 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 = ["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){
//skip
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
};
} else {
createXHR = function(){
throw new Error("No XHR object available.");
};
}
return createXHR(); //新增按合适方式执行的函数
}
代码解释:这个惰性载入的createXHR()
中,if语句的每一个分支都会为createXHR变量赋值,有效覆盖了原有的函数。最后一步便是调用新赋的函数。下一次调用createXHR()
时,会直接调用被分配的函数。
- 在声明函数时就指定适当的函数
1 | var createXHR = (function(){ |
4. 函数绑定
函数绑定: 要创建一个函数,可以在特定的this
环境中以指定参数调用另一个函数。
用处: 和回调函数、事件处理程序、setTimeout()、setInterval()一起使用,以便在将函数作为变量传递的同时保留代码执行环境。
函数bind()
:接受一个函数和一个环境,并返回一个在给定环境中调用给定函数的函数,并且将所有参数原封不动传递过去。
1 | function bind(fn,context){ |
ECMA5方法原生bind(),IE9+、FireFox 4+和Chrome。
5. 函数柯里化
用处: 用于创建已经设置好了一个或多个参数的函数。
方法: 使用闭包返回一个函数。
创建步骤: 调用另一个函数并为它传入要柯里化的函数和必要参数。
1 | function curry(fn){ //不止一个参数 |
curry()
工作目的:将被返回函数的参数进行排序。
1 | function add(num1,num2){ |
更复杂的bind()函数: 函数柯里化作为函数绑定一部分
1 | function bind(fn,context){ //不止两个参数 |
ECMA5的bind()
方法也实现函数柯里化,再传入另一个参数即可。