In this case, the built-in function Number was found. I would like to consider it, because the questions I ask below are found in other functions in the specification.
If we open the specification, we see the following:
20.1.1.1 Number ( value )
When Number is called with argument value, the following steps are
taken:
If no arguments were passed to this function invocation, let n be
+0.
Else, let n be ? ToNumber(value).
If NewTarget is undefined, return n.
Let O be ? OrdinaryCreateFromConstructor(NewTarget,
"%NumberPrototype%", « [[NumberData]] »).
Set O.[[NumberData]] to n.
Return O.
Based on this, I want to ask a few questions:
NewTarget where does it come from?
If this algorithm is used both for the constructor and for a simple conversion to a number, then if NewTarget = undefined this conversion to a number, if NewTarget != undefined, then this calls this function as a constructor.
Let's go further to clarify all the points.
12.3.3.1 Runtime Semantics: Evaluation
NewExpression:new NewExpression
Return ? EvaluateNew(NewExpression, empty).
MemberExpression:new MemberExpressionArguments
Return ? EvaluateNew(MemberExpression, Arguments).
12.3.3.1.1 Runtime Semantics: EvaluateNew ( constructExpr, arguments )
The abstract operation EvaluateNew with arguments constructExpr, and
arguments performs the following steps:
Assert: constructExpr is either a NewExpression or a
MemberExpression.
Assert: arguments is either empty or an Arguments.
Let ref be the result of evaluating constructExpr.
Let constructor be ? GetValue(ref).
If arguments is empty, let argList be a new empty List.
Else,
a. Let argList be ArgumentListEvaluation of arguments.
b. ReturnIfAbrupt(argList).
If IsConstructor(constructor) is false, throw a TypeError exception.
Return ? Construct(constructor, argList).
When you call a function via the new operator (we will act without arguments so easily), we'll see that we have the Return 'line. EvaluateNew (NewExpression, empty) In this line, NewExpression is the Number function, right? If everything is correct go further. Next, we see that in the EvaluateNew algorithm there is a line that looks like this: Let's get the result of evaluating constructExpr. - what does this mean? This means that we need to calculate what is ref before continuing to execute the algorithm? If I'm not mistaken, then ref is a Number function. So we are asked to execute the lines of the algorithm from the Number function? If this is the case, then we are faced with a problem in the Number algorithm because we do not know what value NewTarget has.
That you understood a question consists in that that I do not understand as the Number interacts with the operator new. I ask to help you figure it out.
P.S For voters down: explain what you do not like so that I can change the question for the better, thanks
NewTarget - where does it come from?
From either [[call]]ing a builtin function object or from [[construct]]ing a builtin function object.
If this algorithm is used both for the constructor and for a simple conversion to a number, then if NewTarget = undefined this conversion to a number, if NewTarget != undefined, then this calls this function as a constructor.
That's not a question, that's a (true) statement.
In this line, NewExpression is the Number function, right?
No. The NewExpression constructExpr is an expression, i.e. the abstract syntax tree of whatever operand the new operator has. This could be any expression, for example a PrimaryExpression with an IdentifierReference, that evaluates to the global Number function (or a Reference to it) - when it is being evaluated, and that's exactly what step 3 does.
Related
I've heard multiple explanations what the idea behind assignment in ECMAScript specification is. But which one does the EMCAScript spec actually apply? Let's take a look at a simple practical example:
Assignment by copying values, aka "the classic C++/Java approach".
let a = 4 // assign value 4 to variable a
let b = a // copy value of a into b
a = 5 // reassign a with value 5
Assignment by sharing a reference. Primitive values are immutable, Objects are mutable.
let a = 4 // Assigns a with a reference to the immutable value 4
let b = a // copies the reference of a to b
a = 5 // reassigns a with a reference to 5 (in-place mutation would cause b to change as well)
Arguments for Variant 1:
Most importantly, ECMAScript itself seems to specify the assignment as copying values.
https://tc39.es/ecma262/#sec-declarative-environment-records-setmutablebinding-n-v-s
AssignmentExpression : LeftHandSideExpression = AssignmentExpression
1. If LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral, then
a. Let lref be ? Evaluation of LeftHandSideExpression.
b. If IsAnonymousFunctionDefinition(AssignmentExpression) and IsIdentifierRef of LeftHandSideExpression are both true, then
i. Let rval be ? NamedEvaluation of AssignmentExpression with argument lref.[[ReferencedName]].
c. Else,
i. Let rref be ? Evaluation of AssignmentExpression.
ii. Let rval be ? GetValue(rref).
d. Perform ? PutValue(lref, rval).
e. Return rval.
2. Let assignmentPattern be the AssignmentPattern that is covered by LeftHandSideExpression.
3. Let rref be ? Evaluation of AssignmentExpression.
4. Let rval be ? GetValue(rref).
5. Perform ? DestructuringAssignmentEvaluation of assignmentPattern with argument rval.
6. Return rval.
Branch 1d is particularly interesting for primitives, which ultimately leads to the SetMutableBinding method of the EnvironmentRecord, which states:
https://tc39.es/ecma262/#sec-declarative-environment-records-setmutablebinding-n-v-s
It attempts to change the bound value of the current binding of the
identifier whose name is N to the value V.
Arguments for Variant 2:
On the other hand a lot of documentation suggests that example 1 might be the case. Like the explicit mentioning of immutability of primitive values, which only really makes sense if there would be a possibility to affect other variables by doing so (by having multiple references point to that value).
https://developer.mozilla.org/en-US/docs/Glossary/Primitive?retiredLocale=de
All primitives are immutable; that is, they cannot be altered. It is important not to confuse a primitive itself with a variable assigned a primitive value. The variable may be reassigned to a new value, but the existing value can not be changed in the ways that objects, arrays, and functions can be altered.
This explanation in Eloquent JavaScript I assume also talks about a reference (binding) pointing to a different value.
https://eloquentjavascript.net/04_data.html
Even though number values don’t change, you can use a let binding to keep track of a changing number by changing the value the binding points at.
My guess is, the specification is rather general. Which applies better to variant 1, but it is free to the implementor to implement it the way you want. Is that correct?
Assignment always copies by value, you can easily check that option 2 is not what happens.
What may be sometimes confusing is that if you copy (by value) a pointer and then modify the value that it points to, then the value the original variable points to will always be modified (because they both point to the same memory address). And things like objects and arrays are secretly pointers.
let a = {x: 3};
let b = a;
b.x = 5;
// Now a.x is 5 as well because a and b point to the same memory address
b = {x: 7};
// a.x is still 5 because we changed the value of b
I started reading YDKJS for fun - and found that he's written:
we can do stuff like:
var num = (1.2).toFixed(1)
so - this means that toFixed is being invoked as a member method from an integer value.
So why doesn't this work??
"toFixed" in 1.222
But this works:
"toFixed" in new Number(1.222)
Page 268 of the Es262 spec states:
RelationalExpression : RelationalExpression in ShiftExpression
[...]
Let rref be the result of evaluating ShiftExpression.
Let rval be ? GetValue(rref).
If Type(rval) is not Object, throw a TypeError exception.
So in other words: You can't use in on numbers. Thats just the way it is defined.
new Number however does not create a number, but a number object (an object that inherits from the Number.prototype). That's why you can use in on it, cause its an actual object.
You can still do 12..toFixed(), thats because of a very interesting construct in the spec: The abstract GetValue operation, which will be called when you access a property¹, does call toObject if the target (12 in this case) is not an object, and that will then do the following:
Return a new Number object whose [[NumberData]] internal slot is set to argument.
So in other words: 12..toFixed() is exactly the same as new Number(12).toFixed().
¹ interestingly accessing the property itself does not actually do that according to the spec, if you do a.b that will only look up the value of a and create a reference (Reference(a, "b")). The actual property lookup happens when GetValue gets called on it (however I don't know of any case were a Reference gets lost without calling GetValue on it).
I'm trying to understand the below block of syntax (taken from angular docs to represent the use of angular noop as an 'empty' function)
function foo(callback) {
var result = calculateResult();
(callback || angular.noop)(result);
}
I don't understand the '||' syntax. I tried looking it up but had trouble searching and wasn't really sure what to search.
Thinking of it as 'OR' syntax, it would mean to me if a function was assigned to the callback or if the function was assigned to angular noop would equal true and then a function is being called on true. But obviously that's wrong
Apologies in advance for the newbishness of the question.
- EDIT -
To clarify further, I'm aware of what it does guessing from the example. However, I'm trying to figure out what javascripts rule say that would cause the return statement for (callback1 || callback2) to return a function object instead of a boolean (as implied by the fact that in the example you can call the return of the sub-expression).
This bit
(callback || angular.noop)(result);
is short for:
if (callback) {
callback(result);
} else {
angular.noop(result);
}
It takes advantage of the fact that || is lazily executed. The search term you're looking for is lazy evaluation. To explain the "why" on how this works, we can take a look at the ECMAScript specification, specifically 11.11 Binary Logical Operators,
The value produced by a && or || operator is not necessarily of type Boolean. The value produced will always be the value of one of the two operand expressions. Note that this doesn't mean that you can't depend on an expression such as:
if (a || b) // <-- logical expression will evaluate to the value of a or b, NOT true or false
because JavaScript evaluates boolean values as truthy or falsy, formally defined as the operation ToBoolean() in the ECMAScript specification.
From 9.2 ToBoolean
The abstract operation ToBoolean converts its argument to a value of type Boolean according to Table 11:
Argument
Type Result
Undefined false
Null false
Boolean The result equals the input argument (no conversion).
Number The result is false if the argument is +0, −0, or NaN;
otherwise the result is true.
String The result is false if the argument is the empty String
(its length is zero); otherwise the result is true.
Object True
Basically the statement
(callback || angular.noop)(result);
Can be read as:
Call the function callback or angular.noop with the argument of result
If callback is not defined the OR (||) will be evaluated to call the angular.noop function passing the variable result to the function.
The angular.noop() function is a function that does nothing. More read here https://docs.angularjs.org/api/ng/function/angular.noop
While working on another problem, I created this fiddle:
http://jsfiddle.net/tr2by/
function foo() {
// console.log(_.isBoolean(this));
console.log(this === true);
}
foo.call(true); // object:[object Boolean]
foo.apply(true); // object:[object Boolean]
Is this an example of auto-boxing?
Going from a value type to a reference type.
Here is a wikipedia def.
First of all I assume you are talking about automatic conversion of primitive values to objects. This happens in two cases in JavaScript:
When you pass a primitive value as the this value to .call or .apply (not in strict mode though).
When you are trying to access a "property" of a primitive value, e.g. "foo bar".split().
In the first case the conversion is permanent, i.e. this will indeed reference an object, in the second the conversion only takes place internally for the duration of the evaluation
If you are not interested in the details of the conversion, you can ignore the rest of the answer.
1. Primitive value as this
When a function is exectued and its this value is not an object, it is converted to one, at least in non-strict mode. This is described in §10.4.3 Entering Function Code [spec] in the ECMAScript 5.1 documentation:
The following steps are performed when control enters the execution context for function code contained in function object F, a caller provided thisArg, and a caller provided argumentsList:
If the function code is strict code, set the ThisBinding to thisArg.
Else if thisArg is null or undefined, set the ThisBinding to the global object.
Else if Type(thisArg) is not Object, set the ThisBinding to ToObject(thisArg).
[...]
As you can see in step three the value is converted to an object by calling ToObject [spec].
2. Property access
Something similar happens when you are trying to access properties (§11.2.1 Property Accessors [spec]). The quoted part here explains how the expression foo[bar] is evaluated, i.e. how property access with the bracket notation is evaluated. The part we are interested in applies to dot notation as well.
The production MemberExpression : MemberExpression [ Expression ] is evaluated as follows:
Let baseReference be the result of evaluating MemberExpression.
Let baseValue be GetValue(baseReference).
[...]
8. Return a value of type Reference whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.
The important step is the last one: No matter to what MemberExpression evaluates, it is converted to a value of type Reference [spec]. This is a datatype only used in the specification and contains additional information about how the actual value should be retrieved from the reference (not to be confused with object references in actual JavaScript code!).
To get the "real" value/result from such a reference, the internal function GetValue(V) (§8.7.1) [spec] is called (just like in step 2 in the above algorithm), where it says:
The following [[Get]] internal method is used by GetValue when V is a property reference with a primitive base value. It is called using base as its this value and with property P as its argument. The following steps are taken:
Let O be ToObject(base).
[...]
Example:
Assume we have the expression
var foo = "BAR".toLowerCase();
This is an assignment expression which is evaluated as follows:
The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows:
Let lref be the result of evaluating LeftHandSideExpression.
Let rref be the result of evaluating AssignmentExpression.
Let rval be GetValue(rref).
[...]
Step 1: The left hand side is evaluated, which is the identifier foo. How exactly identifiers are resolved is not important for this.
Step 2: The right hand side is evaluated, i.e. "BAR".toLowerCase(). The internal result of that evaluation will be a reference value, similar to:
REFERENCE = {
base: "BAR",
propertyNameString: "toLowerCase",
strict: false
}
and stored in rref.
Step 3: GetValue(rref) is called. The base of the reference is the value "BAR". Since this is a primitive value, ToObject will be called to convert it to a temporary String object. Furthermore, the reference is actually a property access, so GetValue will eventually call the method toLowerCase on the String object and return the method's result.
Javascript boxes the this argument provided to call and apply in non-strict mode. From MDN:
if the method is a function in non-strict mode code, null and undefined will be replaced with the global object, and primitive values will be boxed.
The other answers provide detailed information about when autoboxing occurs, but here's a couple more things to remember:
Autoboxing does not occur when using the in operator, which throws a TypeError if the value received is not an object. A simple solution is to manually box the object with Object(value).
Some form of autoboxing occurs when iterating using for...of or the spread syntax [...value] which allows strings to be iterated.
Definitive JavaScript by David Flanagan makes a distinction between Objects and Primitives.
He defines the primitives as Number, String, Boolean, Null, and Undefined, as does the standard.
However, would it be more accurate to define a primitive, as subset of object, i.e. to call them Primitive Objects.
Because they have their own methods and are complex entities.
Actual Question
Would Primitive Object be more accurate than Object when defining String, Boolean, and Number?
Objects and primitives are distinct:
typeof 42 === "number"
typeof new Number(42) === "object"
new Number(42) !== 42
However, when necessary, primitives are automatically wrapped by temporary objects, which can be automatically converted back into primitives:
(42).toString() === "42"
new Number(42) == 42
new Number(42) + 1 === 43
Especially in the context of the Java and C# programming languages, this sort of behavior is called autoboxing. As wrapper objects have some confusing characteristics, for example:
Boolean(new Boolean(false)) === true
it is good practice to avoid intentionally storing them in variables and instead use primitives whenever possible.
It's not about semantics, look:
var threePrimitive = 3;
var threeObject = new Number(3);
threePrimitive.toFixed(2); // 3.00
threeObject.toFixed(2); // 3.00
threePrimitive.foo = true
threeObject.foo = true;
threePrimitive.foo; // undefined
threeObject.foo; // true
Primitives are wrapped in objects when you try to call a method on them, but after initial use the object is thrown away.
As for how this is stated in the specification, I'm not 100% sure, but here is what I think (based on the tips left by Bergi in one of his answers. Section 11.2.1 states that the accessor properties should be evaluated as follows:
Let baseReference be the result of evaluating MemberExpression.
Let baseValue be GetValue(baseReference).
(...)
Then in 8.7.1 we see the following:
The following [[Get]] internal method is used by GetValue when V is a
property reference with a primitive base value. It is called using
base as its this value and with property P as its argument. The
following steps are taken:
Let O be ToObject(base).
Let desc be the result of calling the
[[GetProperty]] internal method of O with property name P.
If desc is
undefined, return undefined.
If IsDataDescriptor(desc) is true, return
desc.[[Value]].
Otherwise, IsAccessorDescriptor(desc) must be true so,
let getter be desc.[[Get]]. If getter is undefined, return undefined.
Return the result calling the [[Call]] internal method of getter
providing base as the this value and providing no arguments.
NOTE The
object that may be created in step 1 is not accessible outside of the
above method. An implementation might choose to avoid the actual
creation of the object. The only situation where such an actual
property access that uses this internal method can have visible effect
is when it invokes an accessor function.
Would Primitive Object be more accurate then Object when defining
String, Boolean, and Number?
Please note that I'm not saying that numbers are not objects here, I'm pointing out that it appears ambiguous. This is the kind of thing that confuses JavaScript newcomers.
The distinction is mostly academic, but there is one case where it seems ambiguous: literals represent primitive objects except when the literal appears to represent a number. You can't apply a method directly to a literal integer* symbol:
1.toString();
SyntaxError: identifier starts immediately after numeric literal
…but you can apply methods of Numbers:
Number(1).toString();
'1'
…and a name that contains a number is a Number:
x = 4;
x.toString();
'4'
I think this is actually a parsing problem, but I don't really know why the parser can't tell that 1 is a Number as easily as it can tell that "abc" is a String. I suppose it has to do with the semantic ambiguity of the . symbol. (Is it a decimal point or a method operator?)
*JavaScript doesn't actually have integers. I just mean a symbol that consists entirely of [0-9]+.