问题
I do not understand the behavior of Intl.DateTimeFormat
.
It does not expose the behavior I would expect from a JavaScript object. I would like to understand why?
The following snippet demonstrates that the format
method on DateTimeFormat
can't be overridden. How is this possible?
const itDateTimeFormat1 = new window.Intl.DateTimeFormat('it-CH');
const originalFormat = itDateTimeFormat1.format;
itDateTimeFormat1.format = function(date){ return 'Overriden! ' + originalFormat(date)};
console.log(itDateTimeFormat1.format(new Date())); // -> 13/7/2017
Also deriving from DateTimeFormat
via prototypal inheritance seems not possible. The following snippet throws an error:
const itDateTimeFormat2 = new window.Intl.DateTimeFormat('it-CH');
const wrappedDateTimeFormat = Object.create(itDateTimeFormat2);
wrappedDateTimeFormat.format = function(date){ return 'Overriden! ' };
console.log(wrappedDateTimeFormat.format(new Date()));
// Firefox:
// TypeError: Intl.DateTimeFormat.prototype.format called on value that's not an object initialized as a DateTimeFormat
// Chrome:
// Uncaught TypeError: Method format called on incompatible receiver #<DateTimeFormat>
Why is DateTimeFormat
not behaving like a "normal" JavaScript object?
How is it possible for DateTimeFormat
to prevent overriding a method?
How is it possible for DateTimeFormat
to prevent overriding on a derived object?
回答1:
Original answer
Well, since it's a built-in object - it is good to have it frozen. But you can do things like this just in Javascript with Object.defineProperty.
See the following snipper. You can prevent override of your properties with writeable: false
. (I've used JS 5.1)
var MyCoolConstructor = function () {
Object.defineProperty(this, 'nonWriteable', {
enumerable: false,
configurable: false,
writable: false,
value: function () {return 42;}
});
};
var instance = new MyCoolConstructor();
console.log(instance.nonWriteable()); //42
instance.nonWriteable = function () {return 'overriden';}
console.log(instance.nonWriteable()); //42
How to prevent prototypal inheritance?
Check this simple snippet. You can just check if current context have the same prototype as your constructor.
var MyCoolConstructor = function () {
this.foo = function () {
if (Object.getPrototypeOf(this) === MyCoolConstructor.prototype) {
return 42;
} else {
throw new Error('bad this');
}
};
};
var instance = new MyCoolConstructor();
console.log(instance.foo());
//42
var instance2 = Object.create(instance);
console.log(instance2.foo())
//Bad this
Edit 2
Derived object method override can also be prevented in the same manner, they derive property config. Check this snippet which is combination of previous 2
var MyCoolConstructor = function () {
Object.defineProperty(this, 'foo', {
value: function () {
if (Object.getPrototypeOf(this) === MyCoolConstructor.prototype) {
return 42;
} else {
throw new Error('bad this');
}
},
writeable: false
});
};
var instance = new MyCoolConstructor();
console.log(instance.foo());
//42
var derivedInstance = Object.create(instance);
derivedInstance.foo = function () {
return 'overriden';
};
console.log(derivedInstance.foo());
//Bad this. Can't be overridden because foo property is not writeable
Not cool hacks in 3.. 2.. 1..
If you really want to override smth, Object.defineProperty
come to the rescue.
const itDateTimeFormat2 = new window.Intl.DateTimeFormat('it-CH');
const wrappedDateTimeFormat = Object.create(itDateTimeFormat2);
Object.defineProperty(wrappedDateTimeFormat, 'format', {value: function(date) { return 'Overridden!' + date.toString(); }})
wrappedDateTimeFormat.format()
//"Overriden! ..."
Conclusion
As we've seen with the examples. System objects behaves just like normal configured javascript objects
来源:https://stackoverflow.com/questions/45077313/understanding-intl-datetimeformat-as-a-javascript-object