Contents
  1. 1. Foward
  2. 2. 安全检测类型
  3. 3. 作用域安全的构造函数
  4. 4. 惰性载入函数
  5. 5. 函数绑定

Foward

关于JS函数的一些奇技淫巧,能够有效的提升网页性能。然而迟早会被新特性取代

安全检测类型

通常做法

1
var isArray = value instanceof Array;

利用Object原生方法,可以进行安全检测。至于什么个安全法。

1
alert(Object.prototype.toString.call(value)); //"[object Array]"

利用Object原生方法安全检测,几乎涵盖所有的数据类型

1
2
3
4
5
6
7
8
9
10
11
function isArray(value){
return 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]";
}

甚至支持原生JSON检测

1
2
//检测原生JSON
var isNativeJSON = window.JSON && Object.prototype.toString.call(JSON) == "[object JSON]";

作用域安全的构造函数

1、防止丢失new关键词,而造成的window污染。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//经典的构造函数
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
}
//作用域安全的构造函数
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);
}
}

2、继承链

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
30
31
32
33
34
//多边形
function Polygon(sides){
if (this instanceof Polygon){
this.sides = sides;
this.getArea = function(){
return 0;
}
} else {
return new Polygon(sides);
}
}
//长方形
function Rectangle(width, height){
//继承,并且传递参数
Polygon.call(this, 2);
this.width = width;
this.height = height;
this.getArea = function(){
return this.width * this.height;
}
}
//实例中出现的问题
var rect = new Rectangle(5, 10);
alert(rect.sides); //undefined
//构造函数窃取结合使用原型链或者寄生组合
Rectangle.prototype = new Polygon();
var rect = new Rectangle(5, 10);
alert(rect.sides); //2

关于原型链的问题,我们之后讨论。

惰性载入函数

利用var的函数技巧,来看一个跨浏览器创建XML请求的例子

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
function createXHR(){
//原生支持
if (typeof XMLHttpRequest != "undefined"){
return new XMLHttpRequest();
//IE稳定支持的版本
} else if (typeof ActiveXObject != "undefined"){
if (typeof arguments.callee.activeXString != "string") {
var version = ["MSXML2.DOMDocument.6.0", "MSXML2.DOMDocument.3.0",
"MSXML2.DOMDocument"],
i, len;
for (i=0, len=version.length; i < len; i++){
try {
new ActiveXObject(version[i]);
arguments.callee.activeXString = version[i];
break;
} catch(ex) {
//跳过
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
} else {
throw new Error("No HHR object available.");
}
}

对于每一次调用这个函数,都要进行冗长的条件判断,然而对于同一款浏览器的参数条件都是相同的,为了提升性能,我们可以对这个函数稍加改进。

第一种方法是第一次调用这个函数时根据条件处理指针,此后这个函数就无需进行if-else判断。

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
30
31
function createXHR(){
if (typeof XMLHttpRequest != "undefined"){
createXHR = createXHR(){
return new XMLHttpRequest();
};
} else if (typeof ActiveXObject != "undefined"){
createXHR = createXHR(){
if (typeof arguments.callee.activeXString != "string") {
var version = ["MSXML2.DOMDocument.6.0", "MSXML2.DOMDocument.3.0",
"MSXML2.DOMDocument"],
i, len;
for (i=0, len=version.length; i < len; i++){
try {
new ActiveXObject(version[i]);
arguments.callee.activeXString = version[i];
break;
} catch(ex) {
//跳过
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
};
} else {
createXHR = function(){
throw new Error("No HHR object available.");
};
}
}

我们也可以在载入时就指定这个函数,根据适用条件直接返回一个匿名函数,代价是函数初次载入时牺牲一些性能。

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
30
31
var createXHR = (function(){
if (typeof XMLHttpRequest != "undefined"){
return function(){
return new XMLHttpRequest();
};
} else if (typeof ActiveXObject != "undefined"){
return function(){
if (typeof arguments.callee.activeXString != "string") {
var version = ["MSXML2.DOMDocument.6.0", "MSXML2.DOMDocument.3.0",
"MSXML2.DOMDocument"],
i, len;
for (i=0, len=version.length; i < len; i++){
try {
new ActiveXObject(version[i]);
arguments.callee.activeXString = version[i];
break;
} catch(ex) {
//跳过
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
};
} else {
return function(){
throw new Error("No HHR object available.");
};
}
})();

无论是哪一种方法,在调用此函数的时候都能够提升性能。

函数绑定

先举一个点击的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var handler = {
message: "Event handled",
handleClick: function(event){
alert(this.message);
}
};
var btn = document.getElementById(my-btn);
//Error!this指向错误!
EventUtil.addHandler(btn, "click", handler.handleClick);
//闭包修正this
EventUtil.addHandler(btn, "click", function(event){
handler.handleClick(event);
});

待更

Contents
  1. 1. Foward
  2. 2. 安全检测类型
  3. 3. 作用域安全的构造函数
  4. 4. 惰性载入函数
  5. 5. 函数绑定