tc39 / proposal-optional-chaining

https://tc39.github.io/proposal-optional-chaining/
4.94k stars 75 forks source link

replace Object wrapper strange behiavior #135

Closed jonlepage closed 4 years ago

jonlepage commented 4 years ago

I very love this new addon. But something strange append in some case. Should no more need manually type Object wrapper in some case with this addon. Example Number Test case

Number.prototype.isFinite = function() {
    return Number.isFinite(this)
}

var n1 = 100;
var n2 = Infinity;
var n3 = null;
if(n1?.isFinite()){ }; // return false !
if(n2?.isFinite()){ };
if(n3?.isFinite()){ };
noppa commented 4 years ago

That's not related to optional chaining, n1.isFinite() also returns false.

This happens because when you access n1.isFinite, the number primitive gets converted ("boxed") to a Number object and, in loose mode, your isFinite method is then called with this being the "boxed" Number object instead of the primitive number 100.

Three ways you can get around this

  1. Use isFinite instead of Number.isFinite
  2. Coerce the boxed object to number value first: return Number.isFinite(Number(this))
  3. Use strict mode
    Number.prototype.isFinite = function() {
    'use strict';
    return Number.isFinite(this)
    }

Anyway, not an optional chaining issue.

claudepache commented 4 years ago

I have nothing to add to @noppa’s answer, except that, if I had to give “three ways you can get around this”, they would be:

  1. Use strict mode
  2. Use strict mode
  3. Use strict mode

Strict mode eliminates the trap you've fallen into (namely, autoboxing of primitive values when used as target of method calls), and resolves other gotchas as well.

ljharb commented 4 years ago

(I echo the recommendation)

To clarify, strict mode doesn't change autoboxing in the general case - (100).toString(), eg, works the same in any mode. What strict mode does do is make assigning to a property on an autoboxed primitive an error, rather than a silent failure; it also avoids autoboxing a receiver, so that the this will be the primitive value in strict mode (where in sloppy mode, it would be the boxed object).

I'm not sure this has any relation to optional chaining :-)