Why can't I add properties to a string object in javascript?
I inherited some javascript code another developer wrote. He didn't like the grid component we used throughout the project, so he decided to write his own. The grid he wrote can't sort dates, because it can only bind to strings / numbers. He converts all dates to strings before using them. I looked at the string formatting of date function he wrote, and figured I could just add a date property to the string with the original value, and then when sorting see if the string has a date property and sort based on that. However, it seems like you can't add properties to strings in javascript. I wasn't aware there were certain types you can't add properties to. For example:
<html>
<script>
var test = "test";
test.test = "test inner";
console.log(test);
console.log(test.test);
</script>
test.test will be undefined. Weird. My question is why this code doesn't work? And also, if you can think of any workarounds for sorting dates on that grid (besides actually binding to date objects instead of strings, which would be a pain to fix,) that would be really helpful.
There are 8 language types in JavaScript:
- 7 primitive types: Undefined, Null, Boolean, Number, BigInt, String, and Symbol
- 1 non-primitive type: Object
Values of the primitive types are called primitive values and they cannot have properties.
Values of the Object non-primitive type are called objects an they can have properties.
When you try to assign a property named 'bar'
to a variable foo
, like so:
foo.bar = 'abc';
then the result will depend on the type of the value of foo
:
(a) if the value of foo
is of the type Undefined or Null, then an error will be thrown,
(b) if the value of foo
is of the type Object, then a named property 'bar'
will be defined on the object foo
(if necessary), and its value will be set to 'abc'
,
(c) if the value of foo
is of any other type, then a TypeError
will be thrown in strict mode: “can't assign to property "bar"
on foo
: not an object”. In loose mode, the above assignment operation will be a no op. In either case, the variable foo
will not be changed in any way.
So, as you can see, assigning properties to variables only makes sense if those variables are objects. If that is not the case, then the assignment will either do nothing at all, or even throw an error.
In your case, the variable test
contains a value of the type String, so this:
test.test = "test inner";
does nothing at all.
However, since ES5 introduced accessor properties, there is an exception to what I've said above. Accessor properties allow us to define functions which are invoked whenever the property is either retrieved or set.
For instance:
var str = '';
str.prop;
Here str
is a variable holding a String value. Therefore, accessing a property of that variable should be a no-op (str.prop
merely returns undefined
). This is true with one exception: if String.prototype
contains a accessor property 'prop'
with a defined getter, then that getter will be invoked.
So, if this is defined:
Object.defineProperty( String.prototype, 'prop', {
get: function () {
// this function is the getter
}
});
then this
str.prop;
will invoke that getter function. This also works in strict mode.
Live demo: http://jsfiddle.net/fmNgu/
However, I don't think that adding accessor properties to the built-in prototypes would be a good practice.
If you use a String object you can add properties:
var test = new String("test");
test.test = "test inner";
console.log(test.toString()); // prints out "test"
console.log(test.test); // prints out "test inner"