这在模块模式

时间:2016-07-26 09:10:36

标签: javascript design-patterns revealing-module-pattern

我试图将Revealing Module模式与Constructor模式一起使用来创建一些漂亮的JS!我希望能够创建多个实例,如果" Countdown"像这样:

var c1 = new Countdown();
c1.init();
var c2 = new Countdown();
c2.init();

这些应该是独立的。因此,我没有使用" var"来声明变量,而是使用"这个"在原型上。我引用了这个"这个"在函数内部,但它未定义。我怎样才能访问"这个"?

var Countdown = function() {};

Countdown.prototype = (function(doc) {

    return {
        init: init
    };

    function init() {
        // day
        this.d1 = doc.createElement('div');
        this.d1.setAttribute('class', 'day-1 elem');

        // ... more elements left out here
    }

    function updateView(time) {
        this.d1.textContent = getDays(secs)[0];
    }

    function getDays(secs) {
        var result = 0;
        if (secs > 0) {
            result = secs / (60 * 60 * 24);
        }

        return Math.floor(result);
    }

})(document);

---编辑---

这是我的完整代码:

"use strict";

var Countdown = function() {
    //this.self = this;
};

Countdown.prototype = (function(doc) {

    return {
        initialize: initialize
    };

    function createElements() {
        var countdown = doc.createElement('div');
        countdown.setAttribute('class', 'countdown');

        var heading = doc.createElement('h2');
        heading.textContent = 'Countdown';
        countdown.appendChild(heading);
        document.body.appendChild(countdown);



        // day
        var wrapDay = doc.createElement('div');
        wrapDay.setAttribute('class', 'wrap-day');
        countdown.appendChild(wrapDay);

        this.d1 = doc.createElement('div');
        this.d1.setAttribute('class', 'day-1 elem');
        wrapDay.appendChild(this.d1);

        this.d2 = doc.createElement('div');
        this.d2.setAttribute('class', 'day-2 elem');
        wrapDay.appendChild(this.d2);

        var lblDay = doc.createTextNode('dage');
        wrapDay.appendChild(lblDay);

        var sepDay = doc.createElement('div');
        sepDay.setAttribute('class', 'separator');
        sepDay.textContent = ':';
        countdown.appendChild(sepDay);



        // hour
        var wrapHour = doc.createElement('div');
        wrapHour.setAttribute('class', 'wrap-hour');
        countdown.appendChild(wrapHour);

        this.h1 = doc.createElement('div');
        this.h1.setAttribute('class', 'hour-1 elem');
        wrapHour.appendChild(this.h1);

        this.h2 = doc.createElement('div');
        this.h2.setAttribute('class', 'hour-2 elem');
        wrapHour.appendChild(this.h2);

        var lblHour = doc.createTextNode('timer');
        wrapHour.appendChild(lblHour);

        var sepHour = doc.createElement('div');
        sepHour.setAttribute('class', 'separator');
        sepHour.textContent = ':';
        countdown.appendChild(sepHour);



        // min
        var wrapMin = doc.createElement('div');
        wrapMin.setAttribute('class', 'wrap-min');
        countdown.appendChild(wrapMin);

        this.m1 = doc.createElement('div');
        this.m1.setAttribute('class', 'min-1 elem');
        wrapMin.appendChild(this.m1);

        this.m2 = doc.createElement('div');
        this.m2.setAttribute('class', 'min-2 elem');
        wrapMin.appendChild(this.m2);

        var lblMin = doc.createTextNode('minutter');
        wrapMin.appendChild(lblMin);

        var sepMin = doc.createElement('div');
        sepMin.setAttribute('class', 'separator');
        sepMin.textContent = ':';
        countdown.appendChild(sepMin);



        // sec
        var wrapSec = doc.createElement('div');
        wrapSec.setAttribute('class', 'wrap-sec');
        countdown.appendChild(wrapSec);

        this.s1 = doc.createElement('div');
        this.s1.setAttribute('class', 'sec-1 elem');
        wrapSec.appendChild(this.s1);

        this.s2 = doc.createElement('div');
        this.s2.setAttribute('class', 'sec-2 elem');
        wrapSec.appendChild(this.s2);

        var lblSec = doc.createTextNode('sekunder');
        wrapSec.appendChild(lblSec);
    }

    function initialize() {
        domReady(function() {

            // create DOM
            createElements();

            // get time
            var now = new Date();
            var year = now.getFullYear();
            var month = now.getMonth();
            var dateFinal = new Date(year, month + 1, 1, 0, 0, 0); // first day next month
            var seconds = getSecsLeft(dateFinal);
            var time = getTimeLeftObject(seconds);

            // update view every second
            setInterval(function() {
                seconds = getSecsLeft(dateFinal);
                time = getTimeLeftObject(seconds);
                updateView(time);
            }, 1000);

            // first time
            updateView(time);
        });
    }

    function updateView(time) {
        var days = zeroPadding(time.days);
        var hours = zeroPadding(time.hours);
        var mins = zeroPadding(time.mins);
        var secs = zeroPadding(time.secs);

        this.d1.textContent = days[0];
        this.d2.textContent = days[1];

        this.h1.textContent = hours[0];
        this.h2.textContent = hours[1];

        this.m1.textContent = mins[0];
        this.m2.textContent = mins[1];

        this.s1.textContent = secs[0];
        this.s2.textContent = secs[1];
    }

    function getDays(secs) {
        var result = 0;
        if (secs > 0) {
            result = secs / (60 * 60 * 24);
        }

        return Math.floor(result);
    }
    function getHours(secs) {
        var result = 0;
        if (secs > 0) {
            result = (secs / (60*60)) % 24;
            result = result === 24 ? 0 : result;
        }

        return Math.floor(result);
    }
    function getMins(secs) {
        var result = 0;
        if (secs > 0) {
            result = (secs / 60) % 60;
            result = result === 60 ? 0 : result;
        }

        return Math.floor(result);
    }
    function getSecs(secs) {
        var result = 0;
        if (secs > 0) {
            result = secs % 60;
            result = result === 60 ? 0 : result;
        }

        return Math.floor(result);
    }

    function zeroPadding(num) {
        var result;
        result = num < 10 ? "0" + num : num;

        return new String(result);
    }

    function getTimeLeftObject(seconds) {
        var secs = getSecs(seconds);
        var mins = getMins(seconds);
        var hours = getHours(seconds);
        var days = getDays(seconds);

        return {
            days: days,
            hours: hours,
            mins: mins,
            secs: secs
        };
    }

    function getSecsLeft(dateFinal) {
        var result = (dateFinal - new Date()) / 1000;
        return result < 0 ? 0 : result;
    }

    function domReady(callback) {
        document.readyState === "interactive" || document.readyState === "complete" ? callback() : document.addEventListener("DOMContentLoaded", callback);
    }

})(document);

1 个答案:

答案 0 :(得分:4)

您似乎在updateView

中呼叫setInterval
function init() {
    // day
    this.d1 = doc.createElement('div');
    this.d1.setAttribute('class', 'day-1 elem');

    var update = updateView.bind(this); // you need to bind updateView context
    setInterval(function() {
       var time = ???
       update(time); // `this` will be current instance
    }, 1000)
}

UPD 由于您要在domReady回调中设置间隔,因此您需要先绑定回调本身或预先绑定updateView

function initialize() {
    domReady(function() {

        // create DOM
        createElements.call(this); // call with current context

        // get time
        var now = new Date();
        var year = now.getFullYear();
        var month = now.getMonth();
        var dateFinal = new Date(year, month + 1, 1, 0, 0, 0); // first day next month
        var seconds = getSecsLeft(dateFinal);
        var time = getTimeLeftObject(seconds);

        var update = updateView.bind(this); 

        // update view every second
        setInterval(function() {
            seconds = getSecsLeft(dateFinal);
            time = getTimeLeftObject(seconds);
            update(time);
        }, 1000);

        // first time
        update(time);
    }.bind(this)); //bind callback
}

或者

function initialize() {
    var update = updateView.bind(this),
        create = createElements.bind(this); // prebind functions that use this
    domReady(function() {

        // create DOM
        create(); //call prebinded function

        // get time
        var now = new Date();
        var year = now.getFullYear();
        var month = now.getMonth();
        var dateFinal = new Date(year, month + 1, 1, 0, 0, 0); // first day next month
        var seconds = getSecsLeft(dateFinal);
        var time = getTimeLeftObject(seconds);

        // update view every second
        setInterval(function() {
            seconds = getSecsLeft(dateFinal);
            time = getTimeLeftObject(seconds);
            update(time);
        }, 1000);

        // first time
        update(time);
    });
}