JavaScript组件:编码实现和算法(2)

http://www.itjxue.com  2015-08-06 23:09  来源:未知  点击次数: 

我很懒,我只想传 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 对象三段式是什么?

  1. 定义对象的构造函数
  2. 在原型上定义属性和方法
  3. 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 可以让你少写一些代码。

(责任编辑:IT教学网)

更多

推荐Javascript/Ajax文章