Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get type of this keyword in Javascript? [duplicate]

I'm manipulating the prototype of Object so that I can add some extension methods.
I've found out that typeof operator always returns object in case the operand is this:

Object.prototype.logType = function () { console.log(typeof this); }
"Hello".logType() 

output of code above is object instead of string. I know that in JavaScript everything is indeed an object, However I need to know the exact type of the value of this. How can I achieve that?

like image 238
Shahryar Saljoughi Avatar asked Dec 18 '22 11:12

Shahryar Saljoughi


2 Answers

When you call a method on a primitive, JS automatically wraps that primitive in its associative object wrapper, so:

"Hello".logType()  

becomes:

new String("Hello").logType() 

hence, this inside of your logType function refers to the wrapped primitive value, giving you an object. You can call .valueOf() to grab the primitive value wrapped in the object:

Object.prototype.logType = function () { console.log(typeof this.valueOf()); }

"Hello".logType(); // string
(1).logType(); // number
true.logType(); // boolean
1n.logType(); // bigint
Symbol().logType(); // symbol
(() => {}).logType(); // function
({}).logType(); // object

Or, you can use strict mode as suggested in the comments, as that keeps this as the original primitve:

Object.prototype.logType = function () { "use strict"; console.log(typeof this); }

"Hello".logType(); // string
(1).logType(); // number
true.logType(); // boolean
1n.logType(); // bigint
Symbol().logType(); // symbol
(() => {}).logType(); // function
({}).logType(); // object
like image 154
Nick Parsons Avatar answered Dec 28 '22 12:12

Nick Parsons


When passed as this outside of strict mode, you have the very rare case that you encounter a primitive in their wrapped object form ("boxed"), as instance of String:

enter image description here

You can therefore check if your method was called on a string using this instanceof String instead of typeof this === 'string'. If you want to differentiate between strings and objects that inherit from String, you could use this.constructor === String instead.

To get a "regular" string back (or number for Number, or boolean from Boolean, etc.), you can call this.valueOf()

(This means you could also write typeof this.valueOf() - but note that this may be misleading because any object could return, say, a string from its valueOf method without actually having been a string originally.)

Note: You cannot differentiate between 'abc'.yourMethod() and new String('abc').yourMethod() this way because you get an instance of String either way.

(Also interesting: Seems like for newer types like BigInt or Symbol you cannot manually create such a wrapper instance, new BigInt(1n) will fail. But (function () { return this }).call(1n) would achieve the same, although I have no idea why anybody would want that...)


All that said: The easiest way to get the exact behavior you want (this being the actual string) is by defining your function in a context that is in strict mode:

(function {
  'use strict'
  Object.prototype.logType = function () { console.log(typeof this); }
})()

Now it will work as intended.

like image 27
CherryDT Avatar answered Dec 28 '22 11:12

CherryDT