我想格式化这样的日期值:
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-helper的问题是它会交换大写和小写的'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");
答案 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";
};