Let's look at those examples:
var a = 1;
var b = { toString:function() {return '1'} };
var c = 1;
a + b + c === "111" // true
It is pretty mind blowing. I know that JS interpreter performs ToPrimitive or ToString operations when we use + operator. But why is object b gets converted to a string when there is no hint PreferredType. Thus it is probably using ToString operation.
Another note: it is only gets converted to string if there is toString method exists on object, why? And if I call that method "toNumber", why it is not converted to number?
Why JavaScript behaves like that?
But why is object b gets converted to a string when there is no hint PreferredType.
When no hint is passed, then the object's valueOf method will be called first. But since b.valueOf() doesn't return a primitive value (it returns the object itself by default), b.toString() will be called next.
See the specification.
The conversion rule can be summarized as follows:
If there is no hint or hint is number, call valueOf first.
If hint is string, call toString first.
If the return value is not is not a primitive value, call the other method.
If the return value is still not a primitve, throw an error.
it is only gets converted to string if there is toString method exists on object, why?
Not sure I understand this statement. Every object has a toString method. If you try to perform this operation on an object without a toString method (via Object.create(null)), an error is thrown.
And if I call that method "toNumber", why it is not converted to number?
Because toNumber has no meaning in JavaScript. toString and valueOf are the two "magic" methods via which objects are converted to primitive:
var n = 1;
var o = {
toString() { return 'bar'; },
valueOf() { return 2; }
};
console.log(n + o);
console.log(String(o));
If none of the methods return a primitive, you would get an error as well.
var n = 1;
var o = {
toString() { return this; },
};
console.log(n + o);
These two methods and their naming seems kind of arbitrary. From ES6 on, the preferred way to define a conversion function is to use the well-known ##toPrimitive symbol:
var a = 1;
var b = { [Symbol.toPrimitive]: function() {return 1} };
var c = 1;
console.log(a + b + c);
##toPrimitive is called before valueOf or toString are called.
Why JavaScript behaves like that?
Because that's how it is defined in the specification. If you want to know the rationale behind that, you have to ask the people who made that decision.
Related
In javascript, when using add sign (+) to concatenate a string and
another variable, that variable will implicitly call its toString method if it is not a string. To verify this, I made a constructor called Apple.
function Apple(name) {
this.name = name;
}
Apple.prototype.toString = function() {
console.log('Apple.prototype.toString called.');
return this.name;
};
var apple = new Apple('Thai apple');
var msg = apple + ' tastes good.'
console.log(msg)
It works as I expected: when calculating apple + ' tastes good',
Apple.prototype.toString is called.
Then I did a similar experiment on Number type.
Number.prototype.num2str = Number.prototype.toString;
Number.prototype.toString = function() {
console.log('new Number.prototype.toString called.');
return this.num2str();
}
var msg = 'num = ' + 123;
console.log(msg);
After running it, I noticed that Number.prototype.toString is not called.
I'm confused. Why doesn't it work like the previous example?
Why doesn't it work like the previous example?
toString is only called if the value is an object (but see below). 123 is not an object, it's a primitive (number) value. Converting primitive values to string values follows different rules. See §7.1.12 in the ES2016 spec, and §7.1.12.1 specifically numbers (too long to quote here) for how values are converted to strings.
Primitive values are not coerced to objects when the + operator is used.
However, even if you'd create a number object it wouldn't work. That's because toString is not actually called for number objects. Why is that?
When performing addition, the following steps happen:
[...]
5. Let lprim be ? ToPrimitive(lval).
6. Let rprim be ? ToPrimitive(rval).
[...]
Both values are converted to primitive values first before they are converted to a number or a string specifically (a primitive value can be a string, number, boolean, null or undefined).
Converting objects to primitive values this way will ultimately calls valueOf first. Only if the return value of that function is not a primitive value will toString be called.
Because new Number(123).valueOf() returns a primitive value, toString will not be called!
Here is your example adjusted for valueOf:
Number.prototype.valueOf = function() {
console.log('new Number.prototype.valueOf called.');
return 'something';
}
var msg = 'num = ' + new Number(123);
console.log(msg);
NB: toString and valueOf are actually outdated ways of converting objects to strings/numbers/primitives. Since ES6, the new is to call the ##toPrimitve method of the object. Only if that doesn't exist, toString or valueOf will be called (see §7.1.1 ToPrimitive).
This question already has answers here:
Javascript using prototype how can I set the value of "this" for a number?
(3 answers)
Closed 6 years ago.
I try to set a number directly from a prototype method.
Usually, a new value is returned.
this of a number object, is also an object. But I guess not a reference. (?)
I have this:
Number.prototype.bitSet = function(bit) {
return this | (1<<bit);
};
But want this:
Number.prototype.bitSet = function(bit) {
this.value = this | (1<<bit);
};
this.value is a pseudo property. Becuase this sould be a reference of the number and without that, you'll overwrite it. But the question is: Is this really a reference to the source number? Is it possible to do that? Assign the value directly to the number who called this method?
var num = 0;
num.bitSet(9);
console.log(num); // num = 512
Btw. chrome console prints [[PrimitiveValue]] for the number.
TL;DR - You can't do that, your initial version of bitSet is how you need to define it. You'll need to save its return value when you use it, e.g., x = x.bitSet(2). You can create your own mutable number object, though, if you like. (More on that below.)
Just for clarity (you probably know this): JavaScript has both number primitives and Number objects. Normally, you're dealing with primitives. The reason Number.prototype works is that a temporary object is created using the primitive's value when a method is called on it. Unless something explicitly saves the object, though, it's as though we were just dealing with primitives.
Numbers are not mutable in JavaScript.1 So your bitSet method cannot change the numeric value of what it's called on; instead, it has to return a new number with the changes made (e.g., your original version).
Note that even if you could change a Number object's value, you're almost never dealing with a number object in code outside functions you've assigned to Number.prototype. For instance:
Number.prototype.bitSet = function(bit) {
return this | (1<<bit);
};
var x = 32;
x = x.bitSet(2);
console.log(x); // 36
console.log(typeof x); // "number", not "object"
var o = new Number(36);
console.log(typeof o); // "object"
In the above, when x = x.bitSet(2); is executed, the number primitive is converted to a temporary Number object, your bitSet method is called, and then the result is whatever your bitSet method returns; unless bitSet does something to store this somewhere, the temporary object is then thrown away. (That's the theory; in fact, your JavaScript engine may well optimize away the object entirely, if it can determine that the code in your function only uses the number as though it were a primitive number.)
So suppose in my code above, we did something to change the state of the Number object in that x.bitSet(2) line. Since that object is temporary and not stored anywhere (unless we store it; it's not in x, x contains a primitive number), whatever we stored on the object would be lost. We can even prove that:
Number.prototype.test = function() {
this.foo = Math.random();
console.log("this.foo", this.foo); // some number
};
var x = 42;
x.test();
console.log(typeof x); // "number", not "object"
console.log("x.foo", x.foo); // undefined
this was definitely an object, we added a property to it and used that property. But x still had the primitive.
You could have your own mutable number type, though:
function MyNumber(value) {
this.value = typeof value === "number" ? value : 0;
}
MyNumber.prototype.bitSet = function(bit) {
this.value = this.value | (1 << bit);
};
MyNumber.prototype.valueOf = function() {
return this.value;
};
MyNumber.prototype.toString = function() {
return this.value.toString();
};
// Usage:
var m = new MyNumber(42);
m.bitSet(2);
console.log(String(m)); // "46"
var n = m + 5;
console.log(n); // 51
The valueOf function is called any time the JavaScript engine needs to convert your number object to a number. toString is called when the JavaScript engine needs to convert your number object to a string.
Or in ES2015:
class MyNumber {
constructor(value) {
this.value = typeof value === "number" ? value : 0;
}
bitSet(bit) {
this.value = this.value | (1 << bit);
}
valueOf() {
return this.value;
}
toString() {
return this.value.toString();
}
}
// Usage:
var m = new MyNumber(42);
m.bitSet(2);
console.log(String(m)); // "46"
var n = m + 5;
console.log(n); // 51
1 "Numbers are not mutable in JavaScript" Technically, that's not true. Primitive numbers are not mutable, but Number objects are — but their underlying numeric value (what the spec calls its [[NumberData]]) cannot be changed. (Number objects can have other properties with state that can be changed, just not their numeric value.) So "Numbers are not mutable in JavaScript" is a reasonable shorthand statement, if not perfectly correct.
What are the exact circumstances for which a return statement in Javascript can return a value other than this when a constructor is invoked using the new keyword?
Example:
function Foo () {
return something;
}
var foo = new Foo ();
If I'm not mistaken, if something is a non-function primitive, this will be returned. Otherwise something is returned. Is this correct?
In other words, what values can something take to cause (new Foo () instanceof Foo) === false?
The exact condition is described on the [[Construct]] internal property, which is used by the new operator:
From the ECMA-262 3rd. Edition Specification:
13.2.2 [[Construct]]
When the [[Construct]] property for a Function object F is
called, the following steps are taken:
Create a new native ECMAScript object.
Set the [[Class]] property of Result(1) to "Object".
Get the value of the prototype property of F.
If Result(3) is an object, set the [[Prototype]] property of Result(1) to Result(3).
If Result(3) is not an object, set the [[Prototype]] property of Result(1) to the original Object prototype object as
described in 15.2.3.1.
Invoke the [[Call]] property of F, providing Result(1) as the this value and
providing the argument list passed into [[Construct]] as the
argument values.
If Type(Result(6)) is
Object then return Result(6).
Return Result(1).
Look at steps 7 and 8, the new object will be returned only if the
type of Result(6) (the value returned from the F constructor
function) is not an Object.
Concrete examples
/*
ECMA 262 v 5
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
"4.3.2
primitive value
member of one of the types Undefined, Null, Boolean, Number, Symbol, or String as defined in clause 6"
*/
var Person = function(x){
return x;
};
console.log(Person.constructor);
console.log(Person.prototype.constructor);
console.log(typeof(Person));
console.log(typeof(Person.prototype));
function log(x){
console.log(x instanceof Person);
console.log(typeof x);
console.log(typeof x.prototype);
}
log(new Person(undefined));
log(new Person(null));
log(new Person(true));
log(new Person(2));
log(new Person(""));
//returns a function not an object
log(new Person(function(){}));
//implementation?
//log(new Person(Symbol('%')));
I couldn't find any documentation on the matter, but I think you're correct. For example, you can return new Number(5) from a constructor, but not the literal 5 (which is ignored and this is returned instead).
As a side note, the return value or this is just part of the equation.
For example, consider this:
function Two() { return new Number(2); }
var two = new Two;
two + 2; // 4
two.valueOf = function() { return 3; }
two + 2; // 5
two.valueOf = function() { return '2'; }
two + 2; // '22'
As you can see, .valueOf() is internally used and can be exploited for fun and profit. You can even create side effects, for example:
function AutoIncrementingNumber(start) {
var n = new Number, val = start || 0;
n.valueOf = function() { return val++; };
return n;
}
var auto = new AutoIncrementingNumber(42);
auto + 1; // 43
auto + 1; // 44
auto + 1; // 45
I can imagine this must have some sort of practical application. And it doesn't have to be explicitly a Number either, if you add .valueOf to any object it can behave as a number:
({valueOf: function() { return Math.random(); }}) + 1; // 1.6451723610516638
You can exploit this to make an object that always returns a new GUID, for instance.
Trying to put a few points in simpler words.
In javascript, when you use a new keyword on a function and if,
function does not return anything, it will return an intended object
function User() {
this.name = 'Virat'
}
var user = new User();
console.log(user.name); //=> 'Virat'
function returns any truthy complex object [object, array, function etc], that complex object takes priority and user variable will hold the returned complex object
function User() {
this.name = 'Virat';
return function(){};
}
var user = new User();
console.log(user.name); //=> undefined
console.log(user); //=> function
function returns any literal, constructor takes priority and it will return an intended object
function User() {
this.name = 'Virat';
return 10;
}
var user = new User();
console.log(user.name); //=> 'Virat'
When you are using the new keyword, an object is created. Then the function is called to initialise the object.
There is nothing that the function can do to prevent the object being created, as that is done before the function is called.
This question already has answers here:
Why isn't this object being passed by reference when assigning something else to it?
(4 answers)
Closed 8 years ago.
In the below code we are passing an object. So, according to javascript we are passing a reference and manipulating.
var a = new Number(10);
x(a);
alert(a);
function x(n) {
n = n + 2;
}
But 10 is alerted instead of 12. Why?
n is local to x and first it is set to the same reference as global a. The right hand side n + 2 is then evaluated to be a number (primitive).
The left hand side of the assignment, n, is never evaluated, it is just an identifier there. So our local variable is now set to the primitive value of the right hand side. The value referenced by a is never actually modified. See
var a = new Number(10);
x(a);
alert(a); // 10
function x(n) {
alert(typeof n); // object
n = n + 2;
alert(typeof n); // number
}
When you compute
n + 2
this results in a new "native number" even if n is indeed a Number object instance.
Assigning to n then just changes what the local variable n is referencing and doesn't change the Number object instance. You can see that with
n = new Number(10);
console.log(typeof n); // ---> "object"
console.log(n + 2); // ---> 12
console.log(typeof (n+2)); // ---> "number"
n = n + 2;
console.log(typeof n); // ---> "number"
In Javascript (or Python or Lisp) there's no way to pass the "address" of a variable so that the called function mutates it. The only thing you can do is passing a setter function... for example:
function foo(setter) {
setter(42);
}
funciton bar() {
var x = 12;
foo(function(newx){x = newx;});
console.log(x); // ---> 42
}
Let me try to answer it with examples:
function modify(obj) {
// modifying the object itself
// though the object was passed as reference
// it behaves as pass by value
obj = {c:3};
}
var a = {b:2}
modify(a);
console.log(a)
// Object {b: 2}
function increment(obj) {
// modifying the value of an attribute
// working on the same reference
obj.b = obj.b + 1;
}
var a = {b:2}
increment(a);
console.log(a)
// Object {b: 3}
function augument(obj) {
// augument an attribute
// working on the same reference
obj.c = 3;
}
var a = {b:2}
augument(a);
console.log(a)
// Object {b: 2, c: 3}
Please refer the JSFiddle for working demo.
The answer is rather simple: because ECMAScript is pass-by-value and not pass-by-reference, and your code proves that. (More precisely, it is call-by-sharing, which is a specific kind of pass-by-value.)
See Is JavaScript a pass-by-reference or pass-by-value language? for some additional insight.
ECMAScript uses pass-by-value, or more precisely, a special case of pass-by-value where the value being passed is always a pointer. This special case is also sometimes known as call-by-sharing, call-by-object-sharing or call-by-object.
It's the same convention that is used by Java (for objects), C# (by default for reference types), Smalltalk, Python, Ruby and more or less every object-oriented language ever created.
Note: some types (e.g.) Numbers are actually passed directly by value and not with an intermediary pointer. However, since those are immutable, there is no observable behavioral difference between pass-by-value and call-by-object-sharing in this case, so you can greatly simplify your mental model by simply treating everything as call-by-object-sharing. Just interpret these special cases as internal compiler optimizations that you don't need to worry about.
Here's a simple example you can run to determine the argument passing convention of ECMAScript (or any other language, after you translate it):
function isEcmascriptPassByValue(foo) {
foo.push('More precisely, it is call-by-object-sharing!');
foo = 'No, ECMAScript is pass-by-reference.';
return;
}
var bar = ['Yes, of course, ECMAScript *is* pass-by-value!'];
isEcmascriptPassByValue(bar);
console.log(bar);
// Yes, of course, ECMAScript *is* pass-by-value!,
// More precisely, it is call-by-object-sharing!
If you are familiar with C#, it is a very good way to understand the differences between pass-by-value and pass-by-reference for value types and reference types, because C# supports all 4 combinations: pass-by-value for value types ("traditional pass-by-value"), pass-by-value for reference types (call-by-sharing, call-by-object, call-by-object-sharing as in ECMAScript), pass-by-reference for reference types, and pass-by-reference for value types.
(Actually, even if you don't know C#, this isn't too hard to follow.)
struct MutableCell
{
public string value;
}
class Program
{
static void IsCSharpPassByValue(string[] foo, MutableCell bar, ref string baz, ref MutableCell qux)
{
foo[0] = "More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.";
foo = new string[] { "C# is not pass-by-reference." };
bar.value = "For value types, it is *not* call-by-sharing.";
bar = new MutableCell { value = "And also not pass-by-reference." };
baz = "It also supports pass-by-reference if explicitly requested.";
qux = new MutableCell { value = "Pass-by-reference is supported for value types as well." };
}
static void Main(string[] args)
{
var quux = new string[] { "Yes, of course, C# *is* pass-by-value!" };
var corge = new MutableCell { value = "For value types it is pure pass-by-value." };
var grault = "This string will vanish because of pass-by-reference.";
var garply = new MutableCell { value = "This string will vanish because of pass-by-reference." };
IsCSharpPassByValue(quux, corge, ref grault, ref garply);
Console.WriteLine(quux[0]);
// More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.
Console.WriteLine(corge.value);
// For value types it is pure pass-by-value.
Console.WriteLine(grault);
// It also supports pass-by-reference if explicitly requested.
Console.WriteLine(garply.value);
// Pass-by-reference is supported for value types as well.
}
}
var a = new Number(10);
x(a);
alert(a);
function x(n) {
n = n + 2; // NOT VALID as this would essentially mean 10 = 10 + 2 since you are passing the 'value' of a and not 'a' itself
}
You need to write the following in order to get it working
var a = new Number(10);
x(a);
alert(a);
function x(n) {
a = n + 2; // reassign value of 'a' equal to the value passed into the function plus 2
}
JavaScript parameter passing works similar to that of Java. Single values are passed by value, but object attributes are passed by reference via their pointer values. A value itself will not be modified in a function, but attributes of an object would be modified.
Consider the following code:
function doThis(param1, param2) {
param1++;
if(param2 && param2.value) {
param2.value++;
}
}
var initialValue = 2;
var initialObject = {value: 2};
doThis(initialValue, initialObject);
alert(initialValue); //2
alert(initialObject.value); //3
http://jsfiddle.net/bfm01b4x/
When I do:
var person = new Object();
person.name = "alex";
console.log(person)
output is:
Object { name="alex"}
However, say I drop the "new" word and do:
var person = Object();
person.name = "alex";
console.log(person)
Output is also:
Object { name="alex"}
Why?
Because some built-in functions are just defined to act this way. For example see ES5 15.2.1.1 for Object:
15.2.1.1 Object ( [ value ] )
When the Object function is called with no arguments or with one argument value, the following steps are taken:
If value is null, undefined or not supplied, create and return a new Object object exactly as if the standard built-in Object constructor had been called with the same arguments (15.2.2.1).
Return ToObject(value).
They test whether they have been called with new or not and if not act like they'd have been called with new.
Not all constructors work like this. For example Date will return a string when called without new.
You can implement this yourself:
function Foo() {
if(!(this instanceof Foo)) {
return new Foo();
}
// do other init stuff
}
Foo() and new Foo() will act the same way (it gets more tricky with variable arguments though).
Since your example is an Object type of built-in function, as it is answered above it is the same for this type, it does not work the same way for most of the other built-in functions such as Number(). You should be very careful when invoking them with the 'new' keyword or not. Because by default the 'new' keyword with a function constructor returns an object, not a primitive type directly. So you can not, for example, check strict equality on two variables that one of them is declared and assigned using new Number() , and the other is with Number()
An example would be:
var num1 = Number(26);
var num2 = new Number(26);
num1 == num2; // returns true
num1 === num2; // returns false
You may checkout the difference at the console log:
console.log(num1);
> 26
console.log(num2);
> Number {26}
> __proto__: Number
> [[PrimitiveValue]]: 26