JavaScript高级程序设计笔记(16)-高级技巧

高级函数

函数柯里化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function curry(fn){
var args = Array.prototype.slice.call(arguments, 1);
return function(){
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return fn.apply(null, finalArgs);
}
}

function add(num1, num2){
return num1 + num2;
}

var curriedAdd = curry(add, 5);
console.log(curriedAdd(3));

var curriedAdd1 = curry(add, 5, 13);
console.log(curriedAdd1());

利用函数柯里化,可以构造出更为复杂的bind()函数。

1
2
3
4
5
6
7
8
function bind(fn, context){
var args = Array.prototype.slice.call(arguments, 2);
return function(){
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return fn.apply(context, finalArgs);
}
}

防篡改对象

不可扩展对象

1
2
3
4
5
var person = { name: '2107'};
Object.preventExtensions(person);

person.age = 1;
console.log(person.age);//undefined

调用Object.preverExtensions()方法后,就不能给person对象添加新属性和方法了,对于已有属性和方法,仍然可以修改和删除。另外使用Object.isExtensible()方法可以确定对象是否可以扩展。

1
2
3
4
5
var person = { name: '2107'};
console.log(Object.isExtensible(person));//true

Object.preventExtensions(person);
console.log(Object.isExtensible(person));//false

密封对象

1
2
3
4
5
6
7
8
var person = { name: '2107'};
Object.seal(person);

person.age = 1;
console.log(person.age);//undefined

delete person.name;
console.log(person.name);//2107

Object.isSealed()方法可以确定对象是否被密封了。

冻结对象

最严格的防止篡改级别是冻结对象。冻结的对象既不可扩展,又是密封的。

1
2
3
4
5
6
7
8
9
10
11
var person = {name: '2107'};
Object.freeze(person);

person.age = 29;
console.log(person.age);//undefined

delete person.name;
console.log(person.name);// 2107

person.name = '1901';
console.log(person.name);// 2107

高级定时器

重复定时器

setInterval()定时器有两个问题:
1、 某些间隔会跳过;
2、 多个定时器代码执行之间的间隔可能会比预期的小。
为了避免setInterval()重复定时器的缺点,可以使用链式setTimeout()调用。

1
2
3
4
setTimeout(function(){
//事件处理程序
setTimeout(arguments.callee, 1000);
}, 1000)

Yielding Processes

1
2
3
4
5
6
7
8
9
function chunk(array, process, context){
setTimeout(function(){
var item = array.shift();
prcoess.call(context, item);
if(array.length > 1){
setTimout(argumenets.callee, 100);
}
}, 100)
}

函数节流

第一次调用函数,创建一个定时器,在指定的时间间隔之后运行代码。当第二次调用该函数时,清除前一次的定时器,并设置另一个。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var processor = {
timeoutId: null,
preformProcessing: function(){
//实际执行代码
},
process: function(){
clearTimeout(this.timeoutId);
var that = this;
this.timoutId = setTimeout(function(){
that.performProcessing();
}, 1000)
}
}
processor.process();

简化:

1
2
3
4
5
6
function throttle(method, context){
clearTimeout(method.tId);
method.tId = setTimout(function(){
method.call(context);
}, 100)
}

对于onresize:

1
2
3
4
5
6
7
8
function resizeDiv(){
var div = document.getElementById('myDIv');
div.style.height = div.offsetWidth + 'px';
}

window.onresize = function(){
throttle(resizeDiv);
}

自定义事件

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
function EventTarget(){
this.handlers = {};
}

EventTarget.prototype = {
constructor: EventTarget,
addHandler: function(type, handler){
if(typeof this.handlers[type] == 'undefined'){
this.handlers[type] = [];
}
this.handlers[type].push(handler);
},
fire: function(event){
if(!event.target){
event.target = this;
}
if(this.handlers[event.type] instanceof Array){
var handlers = this.handlers[event.type];
for(var i = 0, len = handlers.length; i < len; i++){
handlers[i](event);
}
}
},
removeHandler: function(type, handler){
if(this.handlers[type] instanceof Array){
var handlers = this.handlers[type];
for(var i = 0, len = handlers.length; i < len; i++){
if(handlers[i] === handler){
break;
}
}
handlers.splice[i, 1];
}
}
}


//使用

function handlerMessage(event){
console.log('Message received: ' + event.message);
}
//创建一个新对象
var target = new EventTarget();
//添加一个事件处理程序
target.addHandler('message', handlerMessage);
//触发事件
target.fire({type:'message', message:'hello world!'});
//删除事件处理程序
target.removeHandler('message', handlerMessage);
//再次触发,无响应
target.fire({type:'message', message: 'hello world'});