-1

How is the output true and why is there a need to explicitly returning the object as the new keyword creates an object and returns it automatically?

var obj = {};    
function A() { return obj; }
function B() { return obj; }
console.log( new A() == new B() );
jonrsharpe
  • 99,167
  • 19
  • 183
  • 334
  • 1
    You might want to read this: https://stackoverflow.com/questions/9817629/how-do-i-compare-2-functions-in-javascript – Paul Jun 26 '20 at 06:59
  • @NathanChampion no that did not help me at all – user8951842 Jun 26 '20 at 07:23
  • 2
    1. The two are equal because they return the *same object*. Object are equal only to themselves. 2. If you don't explicitly return the object, then `new` *will* return difference instances, so they would be inequal. 3. It's not really clear why you really need the whole `new` and two functions for this. It boils down to `obj === obj`, the other things are just distractions. – VLAZ Jun 26 '20 at 07:55
  • Does this answer your question? [how do I compare 2 functions in javascript](https://stackoverflow.com/questions/9817629/how-do-i-compare-2-functions-in-javascript) – Xnero Jun 26 '20 at 08:46
  • I disagree that "how do I compare 2 functions in javascript" is a dupe target. The question here isn't trying to compare *functions* but it's asking for specific outcome comparing the *result* of two functions when called with `new` operator. That's different to comparing two functions themselves. – VLAZ Jun 26 '20 at 09:19

1 Answers1

1

This code here is pretty convoluted for what's happening. It's not that complex it seems it's just throwing things together to be purposefully misleading. I suspect this is an interview question. I wouldn't class it as really good.

Let's break it down for ease:

Object equality

How is the output true

I'll remove the unneeded code to focus on the real thing. The code can be simplified to

var obj = {};    
console.log( obj == obj );

It should be obvious why that would be true - you're comparing the same thing to itself. The result true is expected regardless1 of the value of obj.

One additional thing we can mention here is that objects are only equal to themselves. That's distinct from other primitive types2 where to values that are the same are also equal3. So two different objects will still be different even if they contain similar information:

console.log("foo" === "foo"); //true
console.log(42 === 42);       //true

console.log({foo: "bar"} === {foo: "bar"}); //false
console.log({} === {});                     //false

1 There is one exception - the value NaN.

2 Except Symbols which are primitives but by design each represents a unique value. It's usually not worth discussing them unless specifically focusing on Symbols, hence they are just a footnote here.

3 I can't seem to formulate an explanation so it doesn't sound like a tautology.


Return values for function

why is there a need to explicitly returning the object as the new keyword creates an object and returns it automatically

This is the crux of the problem here. How the new keyword operates.

Yes, new will create a new object instance when called with a function. However, if the function returns a non-null object, then that will be used as the return value and will override the instance creation:

function Foo() {}            // <-- no `return` statement

function Bar() {
  return null;               // <-- returns `null`
}

function Baz() {
  return 42;                 // <-- returns a non-`null` but primitive value
}

function Quux() {
  return { hello: "world" }; // <-- returns an object
}

const foo  = new Foo();

console.log("typeof foo:", typeof foo);
console.log("foo instanceof Foo:", foo instanceof Foo);
console.log("foo:", foo);

const bar  = new Bar();

console.log("typeof bar:", typeof bar);
console.log("bar instanceof Bar:", bar instanceof Bar);
console.log("bar:", bar);

const baz  = new Baz();

console.log("typeof baz:", typeof baz);
console.log("bar instanceof Baz:", baz instanceof Baz);
console.log("baz:", baz);

const quux = new Quux();

console.log("typeof quux:", typeof quux);
console.log("quux instanceof Quux:", quux instanceof Quux);
console.log("quux:", quux);

Therefore if both A and B have return obj in their bodies and obj is an object, then calling new A() is the same as calling A() without the new operator which is therefore the same as just obj. It's analogous for B.

var obj = {};    
function A() { return obj; }

console.log( new A() == A() ); //true
console.log( A() == obj );     //true
console.log( new A() == obj ); //true

There is a slight curve ball here in that the task uses the abstract equality operator (==) which used is called "loose equality". I'm calling it a "curve ball" since it works in some unintuitive ways. However, it's only slight because none of this applies here - == will produce inconsistent results when the two operands are different types since it will trigger abstract equality comparison. It's a common pitfall and hence it's standard to exclusively use strict equality comparison (===) which is consistent. Here is a quick example of inconsistency with ==:

const a = "";
const b = 0;
const c = " ";

//comparing a string and a number - string is converted to a number.
//empty string `a` converts to a zero
console.log(a == b); //true

//comparing a string and a number again.
//spaces are trimmed from `c` and an empty string is left. It's again a zero
console.log(b == c); //true

//comparing two strings. Same base type - no conversion needed.
//two strings with different content are not equal
console.log(a == c); //false

//the `==` operator is not transitive

However, the operands here are not only the same types but literally the same value, so == will work exactly like ===.


Additional information

With all this explanation in place, it's possible that the question is just a setup. If the value of obj is changed then everything changes. If obj is anything other than an object (so, any primitive type, or null), then calling the functions with new will actually produce a new instance and thus the results would be different:

var obj = 42;
function A() { return obj; }
function B() { return obj; }
console.log( new A() == new B() );

I've discussed it above but just in short

  • the function returns a non-object value
  • calling it with new produces a new instance
  • two different instances are never going to be equal

Removing the new operator from one of the function calls will also produce false, as A() will now return the 42 while new B() produces an object. The two would not be equal.

If the new is removed from both the function calls, then the result is going to be the same for almost any value of obj. Anything except NaN.

VLAZ
  • 18,437
  • 8
  • 35
  • 54