I've come across 2 pretty good articles about one of those JavaScript topics that I still find confusing, so I'll write up here some notes for further reference.
Once we have embraced the idea that JavaScript is profoundly Object Based (functions are objects, "inheritance" chain is based on other objects ([[Prototypes]]...), it can come as a shock to learn that not everything in JavaScript is an Object. Same as with Java, we have Primitive Types, that are not real objects (I guess for performance reasons), and same as in Java, these values get automagically boxed (and unboxed) into real Objects when needed. Notice that C#'s equivalent for this are Value types (the Primitive types nomenclature is only used to refer to that subset of value types that have an alias, like int for Integer, bool for Boolean...) and goes one step further by allowing us to declare new Value types (structs).
So, as this post nicely explains we have 5 primitive types:
In JavaScript there are 5 primitive types: undefined, null, boolean, string and number. Everything else is an object. The primitive types boolean, string and number can be wrapped by their object counterparts. These objects are instances of the Boolean, String and Number constructors respectively.
Bear in mind that null and undefined are different from the other primitives as they lack of equivalent Objects to be boxed into and we can't get or set properties on them. I like the nomenclature used for them in this other excellent article that refers to them (along with 0, false, "" and NAaN) as Falsy Values.
Long in short, strings, bools and numbers have an equivalent Object type, String, Boolean and Number, and the runtime takes care of converting from one to another (box/unbox) when needed, for example, each time we access to a property in one of them "myString".length, true.toString(), (5).toFixed()... So, the methods and properties are in the Boolean, Number and String objects, not in the primitive types. We can verify this:
"aa".__proto__; //works fine, "aa" gets boxed and then we get the String.prototype //however Object.getPrototypeOf("aa"); // throws an exception: //TypeError: "aa" is not an object 5 == new Number(5); //true, coercion at work 5 === new Number(5); //false, identity comparison, o coercion applied "aa" instanceof Object; //false "aa" instanceof String; //false new String("aa") instanceof Object; //true
Related to all this, the typeof operator both helps and adds some confusion. It helps by returning a different string value for each primitive type ("string", "number", "boolean", "undefined", "null") and by returning "object" for any other object. However, it also adds some confusion by returning "function" for functions, instead of "object", something that could lead us to think that functions are primitive types, which is false. Functions are objects (myFunction instanceof Object is true)
>>> typeof true; "boolean" >>> typeof 5; "number" >>> typeof "aa"; "string" >>> typeof undefined; "undefined" >>> typeof null; "object" >>> typeof {}; "object" >>> typeof new String("aa"); "object" >>> typeof function(){}; "function"
Just to end up, I'll add that the other day while going through the ES5 documentation (yes, you're right, idiot, get a life and do something more productive... :-D) I ran into the section dedicated to Types. This paragraph fully matches with the Primitive types vs Objects thing.
An ECMAScript language type corresponds to values that are directly manipulated by an ECMAScript programmer using the ECMAScript language. The ECMAScript language types are Undefined, Null, Boolean, String, Number, and Object.
No comments:
Post a Comment