JavaScript组件:编码实现和算法(2)
我很懒,我只想传 fn 和 dependencies 两个属性,不想做额外的事情。好吧,我们来重构一下构造函数:
var _setupTask = function(fn, level, name, dependencies) {
if(typeof fn !== FUNCTION) {
throw new Error('Invalid argument type: fn.');
}
this.fn = fn;
this.level = _validateLevel(level) ? level : LEVEL_NORMAL;
// detect type of name
this.name = typeof name === STRING && name ? name : 't' + _id++;
// dependencies could be retrieved as an 'Object', so use instanceof instead.
this.dependencies = dependencies instanceof Array ? dependencies : [];
};
var T = SmartQueue.Task = function(task) {
if(arguments.length > 1) {
_setupTask.apply(this, arguments);
} else {
_setupTask.call(this, task.fn, task.level, task.name, task.dependencies);
}
// init context/scope and data for the task.
this.context = task.context || window;
this.data = task.data || {};
};
如此一来,原来的构造方式可以继续工作,而上面的懒人可以这样传入一个“残废体”:
var task1 = new SmartQueue.Task({fn: obj.fn, dependencies: obj.dependencies});
当构造函数收到多个参数时,按之前的方案等同处理;否则,视唯一的参数为 Task 对象或“残废体”。这里通过 JavaScript 中的 apply/call 方法将新实例传给重构出来的 _setupTask 方法,作为该方法的上下文 (context, 也有称为 scope), apply/call 是 JavaScript 在方法之间传递上下文的法宝,要用心体会哦。同时,允许用户定义 task.fn 在执行时的上下文,并将自定义的数据传递给执行中的 fn.
经典的 JavaScript 对象三段式是什么?
- 定义对象的构造函数
- 在原型上定义属性和方法
- new 对象,拿来用
所以,下面要为 SmartQueue.Task 对象的原型定义属性和方法。上期分析过 Task (任务)有几个属性和方法,部分属性我们已经在 _setupTask 中定义了,下面是原型提供的属性和方法:
T.prototype = {
enabled: true,
register: function() {
var queue = Q[this.level];
if(_findTask(queue, this.name) !== -1) {
throw new Error('Specified name exists: ' + this.name);
}
queue.push(this);
},
changeTo: function(level) {
if(!_validateLevel(level)) {
throw new Error('Invalid argument: level');
}
level = parseInt(level, 10);
if(this.level === level) {
return;
}
Q[this.level].remove(this);
this.level = level;
this.register();
},
execute: function() {
if(this.enabled) {
// pass context and data
this.fn.call(this.context, this.data);
}
},
toString: function() {
var str = this.name;
if(this.dependencies.length) {
str += ' depends on: [' + this.dependencies.join(', ') + ']';
}
return str;
}
};
如你所见,逻辑非常简单,也许你已经在一分钟内扫过了代码,嘴角不经意间露出一丝心领神会。不过,这里要说的是简单而且通常最不被重视的 toString 方法。在一些高级语言中,为自定义对象实现 toString 方法被作为最佳实践准则而推荐,为什么呢?因为 toString 可以很方便地在调试器中提供有用的信息,可以方便地将对象基本信息写入日志;在统一的编程模式中,实现 toString 可以让你少写一些代码。