将自定义参数应用于匿名JavaScript替换功能?

时间:2015-06-09 13:04:45

标签: javascript

我想格式化这样的日期值:

var d = new Date();
myobj.format(d, "dddd (ddd)   S dd'd'.MM (MMM MMMM).yyyy HH:mm:ss.fff t tt T TT (o) {Z}");

我不想使用date.js,因为date.js太大了,而且stevenlevithan的format-h​​elper的问题是它会交换大写和小写的'M'字符,我想使用C#和JavaScript中的formatString相同。

现在我写了自己的。到目前为止,它的确有效。
但是现在我已经将“格式”函数(和ord等辅助函数)移动到命名空间myobj中,并且在格式函数中我放松了这个上下文(myobj)。

如果我用.apply(this, arguments)调用函数“format”,我得到正确的this-context,但是我松开了参数“m”。

我不想使用命名空间调用ord(myobj.ord(bla)),我想把它称为“this.ord(bla)”或“aaa.ord(bla)” ,所以我可以随意轻松更改命名空间名称。

Sooo ...我如何将一个额外参数传递给replace-regex中的匿名函数,或者如何在不丢失m的情况下获得“this”-context?

/* @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/. 
https://github.com/datejs/Datejs/blob/master/src/core.js
https://code.google.com/p/datejs/wiki/FormatSpecifiers
http://stackoverflow.com/questions/3552461/how-to-format-a-javascript-date
http://blog.stevenlevithan.com/archives/date-time-format
*/




// https://github.com/datejs/Datejs/blob/master/src/globalization/en-US.js
var $i18n =
{
    dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
    abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
    shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
    firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],

    monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
    abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],

    amDesignator: "AM",
    pmDesignator: "PM",
}




var myobj =
{
    // Pad number with 0
    p: function (val, len)
    {
        val = String(val);
        len = len || 2;
        while (val.length < len) val = "0" + val;
        return val;
    }

    // Pad Milliseconds
    , mp: function (d, n)
    {
        var i = 3, res = p(d.getMilliseconds(), 3).substr(0, n);

        for (; i < n; ++i)
            res += "0";

        return res;
    }


    , tzo: function (d)
    {
        var o = d.getTimezoneOffset();
        return (o > 0 ? "-" : "+") + p(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4)
    }


    , tz: function (date)
    {
        var timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
        timezoneClip = /[^-+\dA-Z]/g;
        return (String(date).match(timezone) || [""]).pop().replace(timezoneClip, "");
    }

    , ord: function (num)
    {
        if (num <= 0)
            return num.toString();

        switch (num % 100)
        {
            case 11:
            case 12:
            case 13:
                return num + "th";
        }

        switch (num % 10)
        {
            case 1:
                return num + "st";
            case 2:
                return num + "nd";
            case 3:
                return num + "rd";
            default:
                return num + "th";
        }

    } // End Fn ord



    , format: function (x, formatString)
    {
        // "S dd'd'.MM (MMMM).yyyy ".replace(/(\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S)/g, 
        return formatString.replace(/d{1,4}|M{1,4}|f{1,7}|yy(?:yy)?|([HhmsTt])\1?|[oSZ]|"[^"]*"|'[^']*'/g,
            function (m, aaa)
            {
                console.log("foo");
                console.log(this);
                console.log(aaa);


                if (m.charAt(0) === "\\")
                {
                    return m.replace("\\", "");
                }

                x.h = x.getHours;

                switch (m)
                {
                    case "hh":
                        return p(x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12));
                    case "h":
                        return x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12);
                    case "HH":
                        return p(x.h());
                    case "H":
                        return x.h();
                    case "mm":
                        return p(x.getMinutes());
                    case "m":
                        return x.getMinutes();
                    case "ss":
                        return p(x.getSeconds());
                    case "s":
                        return x.getSeconds();
                    case "yyyy":
                        return p(x.getFullYear(), 4);
                    case "yy":
                        return p(x.getFullYear());
                    case "dddd":
                        return $i18n.dayNames[x.getDay()];
                    case "ddd":
                        return $i18n.abbreviatedDayNames[x.getDay()];
                    case "dd":
                        return p(x.getDate());
                    case "d":
                        return x.getDate();
                    case "MMMM":
                        return $i18n.monthNames[x.getMonth()];
                    case "MMM":
                        return $i18n.abbreviatedMonthNames[x.getMonth()];
                    case "MM":
                        return p((x.getMonth() + 1));
                    case "M":
                        return x.getMonth() + 1;
                    case "t":
                        return (x.h() < 12 ? $i18n.amDesignator.substring(0, 1) : $i18n.pmDesignator.substring(0, 1)).toLowerCase();
                    case "tt":
                        return (x.h() < 12 ? $i18n.amDesignator : $i18n.pmDesignator).toLowerCase();;
                    case "T":
                        return x.h() < 12 ? $i18n.amDesignator.substring(0, 1) : $i18n.pmDesignator.substring(0, 1);
                    case "TT":
                        return x.h() < 12 ? $i18n.amDesignator : $i18n.pmDesignator;
                    case "S":
                        console.log(this);
                        return this.ord(x.getDate());
                    case "fffffff":
                        return mp(x, 7);
                    case "ffffff":
                        return mp(x, 6);
                    case "fffff":
                        return mp(x, 5);
                    case "ffff":
                        return mp(x, 4);
                    case "fff":
                        return mp(x, 3);
                    case "ff":
                        return mp(x, 2);
                    case "f":
                        return mp(x, 1);
                    case "o":
                        return tzo(d);
                    case "Z":
                        return tz(d);
                    default:
                        return m;
                } // End Switch
            } // End Fn
            //.apply(this, arguments)
        );
    }

};




修改 解决方案很简单,只需使用bind而不是apply:

/* @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/. 
https://github.com/datejs/Datejs/blob/master/src/core.js
https://code.google.com/p/datejs/wiki/FormatSpecifiers
http://stackoverflow.com/questions/3552461/how-to-format-a-javascript-date
http://blog.stevenlevithan.com/archives/date-time-format
http://stackoverflow.com/questions/6002808/is-there-any-way-to-get-current-time-in-nanoseconds-using-javascript
*/




// https://github.com/datejs/Datejs/blob/master/src/globalization/en-US.js
var $i18n =
{
    dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
    abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
    shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
    firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],

    monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
    abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],

    amDesignator: "AM",
    pmDesignator: "PM",
}




var myobj =
{
    // Pad number with 0
    p: function (val, len)
    {
        val = String(val);
        len = len || 2;
        while (val.length < len) val = "0" + val;
        return val;
    }

    // Pad Milliseconds
    , mp: function (d, n)
    {
        var i = 3, res = this.p(d.getMilliseconds(), 3).substr(0, n);

        for (; i < n; ++i)
            res += "0";

        return res;
    }


    , tzo: function (d)
    {
        var o = d.getTimezoneOffset();
        return (o > 0 ? "-" : "+") + this.p(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4)
    }


    , tz: function (date)
    {
        var timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
        timezoneClip = /[^-+\dA-Z]/g;
        return (String(date).match(timezone) || [""]).pop().replace(timezoneClip, "");
    }

    , ord: function (num)
    {
        if (num <= 0)
            return num.toString();

        switch (num % 100)
        {
            case 11:
            case 12:
            case 13:
                return num + "th";
        }

        switch (num % 10)
        {
            case 1:
                return num + "st";
            case 2:
                return num + "nd";
            case 3:
                return num + "rd";
            default:
                return num + "th";
        }

    } // End Fn ord

    ,"formatString": function(str) 
    {
        if (!str)
            return str;

        str = str.toString();

        if (arguments.length < 2) 
            return str;

        var t = typeof arguments[1],
            args = "string" == t || "number" == t ? Array.prototype.slice.call(arguments) : arguments[1];

        for (var arg in args) 
            str = str.replace(new RegExp("\\{" + arg + "\\}", "gi"), args[arg]);

        return str
    }

    , "format": function (x, formatString)
    {
        // "S dd'd'.MM (MMMM).yyyy ".replace(/(\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S)/g, 
        return formatString.replace(/d{1,4}|M{1,4}|f{1,7}|yy(?:yy)?|([HhmsTt])\1?|[oSZ]|"[^"]*"|'[^']*'/g,
            function (m)
            {
                var  p = this.p 
                    ,mp = this.mp.bind(this) 
                    ,tzo = this.tzo.bind(this) 
                    ,tz = this.tz.bind(this) 
                    ,ord = this.ord.bind(this);


                x.h = x.getHours;

                if (m.charAt(0) === "\\")
                {
                    return m.replace("\\", "");
                }

                switch (m)
                {
                    case "hh":
                        return p(x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12));
                    case "h":
                        return x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12);
                    case "HH":
                        return p(x.h());
                    case "H":
                        return x.h();
                    case "mm":
                        return p(x.getMinutes());
                    case "m":
                        return x.getMinutes();
                    case "ss":
                        return p(x.getSeconds());
                    case "s":
                        return x.getSeconds();
                    case "yyyy":
                        return p(x.getFullYear(), 4);
                    case "yy":
                        return p(x.getFullYear());
                    case "dddd":
                        return $i18n.dayNames[x.getDay()];
                    case "ddd":
                        return $i18n.abbreviatedDayNames[x.getDay()];
                    case "dd":
                        return p(x.getDate());
                    case "d":
                        return x.getDate();
                    case "MMMM":
                        return $i18n.monthNames[x.getMonth()];
                    case "MMM":
                        return $i18n.abbreviatedMonthNames[x.getMonth()];
                    case "MM":
                        return p((x.getMonth() + 1));
                    case "M":
                        return x.getMonth() + 1;
                    case "t":
                        return (x.h() < 12 ? $i18n.amDesignator.substring(0, 1) : $i18n.pmDesignator.substring(0, 1)).toLowerCase();
                    case "tt":
                        return (x.h() < 12 ? $i18n.amDesignator : $i18n.pmDesignator).toLowerCase();;
                    case "T":
                        return x.h() < 12 ? $i18n.amDesignator.substring(0, 1) : $i18n.pmDesignator.substring(0, 1);
                    case "TT":
                        return x.h() < 12 ? $i18n.amDesignator : $i18n.pmDesignator;
                    case "S":
                        return ord(x.getDate());
                    case "fffffff":
                        return mp(x, 7);
                    case "ffffff":
                        return mp(x, 6);
                    case "fffff":
                        return mp(x, 5);
                    case "ffff":
                        return mp(x, 4);
                    case "fff":
                        return mp(x, 3);
                    case "ff":
                        return mp(x, 2);
                    case "f":
                        return mp(x, 1);
                    case "o":
                        return tzo(x);
                    case "Z":
                        return tz(x);
                    default:
                        return m;
                } // End Switch
            } // End Fn
            .bind(this)
            //.apply(this, arguments)
        );
    }

};


var x = new Date();
myobj.format(x, "dddd (ddd)   S dd'd'.MM (MMM MMMM).yyyy HH:mm:ss.fff t tt T TT (o) {Z}")



myobj.formatString("hello {foo} name", { foo: "bar" });
// myobj.formatString("hello {foo} name");

1 个答案:

答案 0 :(得分:1)

将替换内部的方法移动到对象中自己的方法,并在引用方法时使用bind,这样就可以保留范围。

...
dateRegExp : /d{1,4}|M{1,4}|f{1,7}|yy(?:yy)?|([HhmsTt])\1?|[oSZ]|"[^"]*"|'[^']*'/g,
format: function (x, formatString) {
        return formatString.replace(this.dateRegExp, this._formatFnc.bind(this, x));
},
_formatFnc : function (x, m, aaa) { 
    /* replace code here */ 
    return "qwerty"; 
}
...

如果您不想这样做,您可以随时将其放入varoable并在replace方法中引用它。

var that = this;
return formatString.replace(..., function() {
    console.log(that);
    return "qwerty";
};