Is null a regular primitive in JavaScript? - javascript

There are plenty of discussions about what null in JavaScript actually is. For example, Why is null an object and what's the difference between null and undefined?.
MDN lists null among primitive values and states that it is:
a special keyword denoting a null value; null is also a primitive
value
(The above emphasis is mine)
My last reference will be to Programming JavaScript Applications book by Eric Elliott, which in its Chapter 3. Objects says the following:
In JavaScript, ... even primitive types
get the object treatment when you refer to them with the property
access notations. They get automatically wrapped with an object so
that you can call their prototype methods.
Primitive types behave like objects when you use the property access notations, but you can't assign new properties to them. Primitives
get wrapped with an object temporarily, and then that object is
immediately thrown away. Any attempt to assign values to properties
will seem to succeed, but subsequent attempts to access that new
property will fail.
And indeed the following statements will execute without a problem:
"1".value = 1;
(1).value = "1";
false.value = "FALSE";
while his one
null.value = "Cannot set property of null";
throws Uncaught TypeError. See JS Fiddle.
So at least in this regard, null behaves differently than other primitives.
Is null considered a regular primitive in JavaScript?

Yes it's an actual primitive.
The exceptions for property access are null and undefined, because they have no wrapper type like strings, booleans and numbers do.
ECMAScript 5, Section 4.3.2 primitive
value
member of one of the types Undefined, Null, Boolean, Number, or String
as defined in Clause 8.
NOTE A primitive value is a datum that is represented directly at the
lowest level of the language implementation.

Related

Why is the string literal considered a primitive type in JavaScript?

The official documentation as well as tons of articles on the internet say that 'some string' is a primitive value, meaning that it creates a copy each time we assign it to a variable.
However, this question (and answer to it) How to force JavaScript to deep copy a string? demonstrates that actually V8 does not copy a string even on the substr method.
It would also be insane to copy strings every time we pass them into functions and would not make sense. In languages like C#, Java, or Python, the String data type is definitely a reference type.
Furthermore, this link shows the hierarchy and we can see HeapObject after all.
https://thlorenz.com/v8-dox/build/v8-3.25.30/html/d7/da4/classv8_1_1internal_1_1_sliced_string.html
Finally, after inspecting
let copy = someStringInitializedAbove
in Devtools it is clear that a new copy of that string has not been created!
So I am pretty sure that strings are not copied on assignment. But I still do not understand why so many articles like JS Primitives vs Reference say that they are.
Fundamentally, because the specification says so:
string value
primitive value that is a finite ordered sequence of zero or more 16-bit unsigned integer values
The specification also defines that there are String objects, as distinct from primitive strings. (Similarly there are primitive number, boolean, and symbol types, and Number and Boolean and Symbol objects.)
Primitive strings follow all the rules of other primitives. At a language level, they're treated exactly the way primitive numbers and booleans are. For all intents and purposes, they are primitive values. But as you say, it would be insane for a = b to literally make a copy of the string in b and put that copy in a. Implementations don't have to do that because primitive string values are immutable (just like primitive number values). You can't change any characters in a string, you can only create a new string. If strings were mutable, the implementation would have to make a copy when you did a = b (but if they were mutable the spec would be written differently).
Note that primitive strings and String objects really are different things:
const s = "hey";
const o = new String("hey");
// Here, the string `s` refers to is temporarily
// converted to a string object so we can perform an
// object operation on it (setting a property).
s.foo = "bar";
// But that temporary object is never stored anywhere,
// `s` still just contains the primitive, so getting
// the property won't find it:
console.log(s.foo); // undefined
// `o` is a String object, which means it can have properties
o.foo = "bar";
console.log(o.foo); // "bar"
So why have primitive strings? You'd have to ask Brendan Eich (and he's reasonably responsive on Twitter), but I suspect it was so that the definition of the equivalence operators (==, ===, !=, and !==) didn't have to either be something that could be overloaded by an object type for its own purposes, or special-cased for strings.
So why have string objects? Having String objects (and Number objects, and Boolean objects, and Symbol objects) along with rules saying when a temporary object version of a primitive is created make it possible to define methods on primitives. When you do:
console.log("example".toUpperCase());
in specification terms, a String object is created (by the GetValue operation) and then the property toUpperCase is looked up on that object and (in the above) called. Primitive strings therefore get their toUpperCase (and other standard methods) from String.prototype and Object.prototype. But the temporary object that gets created is not accessible to code except in some edge cases,¹ and JavaScript engines can avoid literally creating the object outside of those edge cases. The advantage to that is that new methods can be added to String.prototype and used on primitive strings.
¹ "What edge cases?" I hear you ask. The most common one I can think of is when you've added your own method to String.prototype (or similar) in loose mode code:
Object.defineProperty(String.prototype, "example", {
value() {
console.log(`typeof this: ${typeof this}`);
console.log(`this instance of String: ${this instanceof String}`);
},
writable: true,
configurable: true
});
"foo".example();
// typeof this: object
// this instance of String: true
There, the JavaScript engine was forced to create the String object because this can't be a primitive in loose mode.
Strict mode makes it possible to avoid creating the object, because in strict mode this isn't required to be an object type, it can be a primitive (in this case, a primitive string):
"use strict";
Object.defineProperty(String.prototype, "example", {
value() {
console.log(`typeof this: ${typeof this}`);
console.log(`this instance of String: ${this instanceof String}`);
},
writable: true,
configurable: true
});
"foo".example();
// typeof this: string
// this instanceof String: false

Why does 'abc'.hasOwnProperty('length') == true

Please help me understand prototype inheritance in this case:
Why does 'abc'.hasOwnProperty('length') return true but 'length' in 'abc' throws an error?
The expression 'abc'.hasOwnProperty('length') is interpreted by JavaScript as
(new String('abc')).hasOwnProperty('length')
Every (capital-S) String instance has its own length property, which gives the length of the string.
JavaScript (lower-case s) string instances are primitives and do not have any properties at all. The use of a string primitive as the left-hand side of the . operator causes the string primitive to be implicitly wrapped in a String object (at least conceptually; the runtime doesn't really have to instantiate a transient object) and that's where the .length property comes from.
The expression length in 'abc' throws an exception because there's no implicit promotion of the primitive 'abc' to a String instance with the in operator. Thus since a primitive cannot have any properties, and the concept makes no sense, it's an exception.

Javascript - how do primitives really work

I have the following code:
String.prototype.isLengthGreaterThan = function(limit){
return this.length > limit;
}
console.log("John".isLengthGreaterThan(3));
Number.prototype.isPositive = function(){
return this > 0;
}
console.log(5.isPositive(3)); //error
The 1st example work, the other doesn't. Why?
From my understanding, primitives are not objects – though they do have access to their function constructor's prototype (Number, String, etc.). So, you can add methods directly to the prototype. In my example above it didn't work in one instance.
I am looking for "under the hood" answer, to understand what happens when you do, for example:
var a = 1;
How does it really have an access to its prototype if it isn't an object?
The dot thing isn't to do with primitives, it's just the syntax of writing numeric literals. In a number, the . is a decimal point, whereas of course that's not the case for a string. To use a method on a literal number, you have two choices:
Parens:
console.log((5).isPositive(3));
Two dots (yes, really):
console.log(5..isPositive(3));
In the second case, it works because the first dot is a decimal point; this means that the dot following can't be a decimal point, and so it's the property accessor operator.
How does it really have an access to it's prototype if it isn't an object.
It's promoted to an object automatically by the JavaScript engine when you do the propety access. In the case of numbers, it's as though you called new Number(5) or similar. In the case of strings, it's as though you called new String("the string"). When the property access is complete, the temporary object is then discarded immediately when the expression is complete. Naturally, the JavaScript engine can optimize the object allocation out, but conceptually that's what happens.
So conceptually:
We do (say) var n = 1; The variable a contains the primitive number value 1.
We do n.isPositive(3); to create a string from it using Number.prototype.toFixed. That's a property access operation:
The engine evaluates the left-hand side, n, and gets the result 1 (a primitive number); this is the base it'll use for the property access operation.
The engine evaluates the right-hand side (isPositive) to determine the property key (name) to look up. In this case it's a literal, so the key is the string "isPositive". This is the property key for the property access operation.
The engine goes to look up the property on the base. Since the base we have is a primitive, the JavaScript engine promotes it (coerces it) to an equivalent Number object.
Since that object doesn't have a "isPositive" property, the engine looks at its prototype, Number.prototype, and finds it; it's a reference to a function.
Various things happen that aren't really germane, and ultimately isPositive is called with this being an object coerced from the primitive value 1. It does its work and generates its return value.
Since the temporary object isn't referenced by anything anymore, it's eligible for garbage collection.
The mechanism by which this happens is a bit scattered in the specification:
The runtime semantics of the property accessor operator return something called a Reference specification type, which basically is a purely abstract specification holding object that will get evaluated later. It says that the base will be the result of evaluating the left-hand side of the property accessor, and the property anme will be the result of evaluting the right-hand side.
The GetValue operation on the Reference type, which says (step 5) that if it's a property reference and the base is primitive, it's coerced via the specification's ToObject operation.
ToObject, which defines the rules for doing that.

Confusion about prototype chain , primitives and objects

in firebug console :
>>> a=12
12
>>> a.__proto__
Number {}
>>> (12).__proto__
Number {}
>>> a.constructor.prototype === (12).__proto__
true
>>> a.constructor.prototype.isPrototypeOf(a)
false
the final line causes me a great confusion as compared to the other lines. also see Constructor.prototype not in the prototype chain?
When you use the . operator with a primitive, the language auto-boxes it with the appropriate Object type (in this case, Number). That's because simple primitive types in JavaScript really are not Object instances.
Thus, the actual left-hand side of
a.__proto__
is not the number 12 but essentially new Number(12). However, the variable "a" continues to be the simple number value 12.
edit — Section 8.7 of the spec "explains" this with typical ECMA 262 moon language. I can't find a clear paragraph that describes the way that a primitive baseValue is treated as a Number, Boolean, or String instance, but that section directly implies it. I think that because those non-primitive synthetic values are ephemeral (they're only "real" while the . or [] expression is being evaluated) that the spec just talks about the behavior without explicitly requiring that an actual Number is constructed. I'm guessing on that however.
#Pointy has explained it very well. Basically, if you want your last statement to be true, you would have to write it like:
a.constructor.prototype.isPrototypeOf(new Number(a));
In JavaScript primitives do not have a prototype chain. Only objects do. A primitive value includes:
Booleans
Numbers
Strings
Null
Undefined
Hence if you call isPrototypeOf with a primitive value then it'll always return false.
If you try to use a boolean, number or string as an object then JavaScript automatically coerces it into an object for you. Hence a.constructor evaluates to new Number(a).constructor behind the scenes. This is the reason you can use a primitive value as an object.
If you wish to use a variable storing a primitive value as an object often then it's better to explicitly make it an object. For example in your case it would have been better to define a as new Number(12). The advantages are:
JavaScript doesn't need to coerce the primitive to an object every time you try to use it as an object. You only create the object once. Hence it's performance efficient.
The isPrototypeOf method in your case will return true as a will be an instance of Number. Hence it will have Number.prototype in its prototype chain.

JS: Distinctions between undefined value and Undefined type, as well as null value and Null type?

Would someone explain the difference between an undefined value and Undefined type, and similarly the same for null values and Null types?
Bonus: why do boolean, string, and number have values, types, and objects, and null and undefined have only values and types (no objects)? If "everything is an object", then one would assume we have objects for all available values, yes? Where's my Infinity and NaN objects?
null and undefined are values. Coincidentally (or just a wise choice), their types are null respectively undefined, as defined null value/type, undefined value/type in the specification. This can also be shown by using the typeof operator:
typeof undefined; // "undefined"
typeof null ; // "null" (in ES6) and "object" in <=ES5 (bug)
A value is associated with a type, which indicates the "kind" of a value.
To give an answer to the question "What is the difference between a value and a type?":
Think of a type as some kind of category and a value is a concrete instance in that category.
For example, we have the type String and a concrete value would be "foo". There can be many different values of type String, but there are only one possible value for the Null and Undefined types, which are null and undefined respectively.
Section 4.3 of the specification is most helpful IMO. Here you find for example the information about strings and the difference between value, type and object.
4.3.16 String value
primitive value that is a finite ordered sequence of zero or more 16-bit unsigned integer.
NOTE: A String value is a member of the String type. Each integer value in the sequence usually represents a single 16-bit unit of UTF-16 text. However, ECMAScript does not place any restrictions or requirements on the values except that they must be 16-bit unsigned integers.
4.3.17 String type
set of all possible String values.
4.3.18 String object
member of the Object type that is an instance of the standard built-in String constructor.
NOTE: A String object is created by using the String constructor in a new expression, supplying a String value as an argument. The resulting object has an internal property whose value is the String value. A String object can be coerced to a String value by calling the String constructor as a function (15.5.1).
It's similar for null and undefined, though they don't have equivalent objects. Why? For that you'd have to ask those who define that language ;)
If "everything is an object", then one would assume we have objects for all available values, yes?
A more correct statement would be "nearly everything is an object", primitive values are not objects obviously, but most of them have an object equivalent (which should actually not be used) and for the others we don't care. Fact is that JavaScript is mainly object oriented.
Where's my Infinity and NaN objects?
Infinity and NaN are values of type Number, so you could create Number objects, like so:
new Number(1/0) // Infinity
new Number("a") // NaN
but you rarely use Number objects anyway.
typeof null === "object"
just to rule that out. null gets treated as an object. Not everything in ECMAscript is an object. The "other side" are the such called "primitive values". Primitive values are, simply spoken, plain values which were not created by any Object constructor. For instance:
var prim = 23;
prim.foo = true;
console.log( 'prim is: ', prim, 'prim.foo is: ', prim.foo ); // "prim is 23, prim.foo is: undefined"
On the other hand
var prim = new Number(23);
prim.foo = true;
console.log( 'prim is: ', +prim, 'prim.foo is: ', prim.foo ); // "prim is 23, prim.foo is: true"
Notice, that I explicitly cast the prim on the second snippet with the plus operator. The second we operate on such a "primitive value", ECMAscript (or more precisely, its engine) will convert that value into its Object representation internally anyway. So you point was actually pretty much correct, "everything is an object".
undefined is a defined value (even if it sounds silly):
'undefined' in window // true
whereas null is a type, which is just part of the language.

Categories