Pregunta

Why does the below code not return this properly? It should just return 'image', rather than all of the letters in an object, shouldn't it?

String.prototype.removeExtension = function(){
    return (this.lastIndexOf('.') !== -1) ? this.substr(0, this.lastIndexOf('.')) : this;
}

'image.jpg'.removeExtension(); // returns 'image'

'image.png.jpg'.removeExtension(); // returns 'image.jpg'

'image'.removeExtension(); // returns String {0: "i", 1: "m", 2: "a", 3: "g", 4: "e", removeExtension: function}
¿Fue útil?

Solución

this always references an object within the context of a scope (*). You need to invoke .toString() for instance, to get the pseudo primitive value out of it.

return this.toString();

If you return this just like that, it'll reference the current instance of that String-object currently invoked.


(*) (only exception is ES5 strict mode, where this also might reference the undefined value

Otros consejos

This is a normal behavior because String is not a char array. So

'image'.removeExtension();

will return a object string not {0: "i", 1: "m", 2: "a", 3: ...

to get a particular char use 'image'.charAt(3); // g

There's a difference between a primitive string value and a String object.

'foo'             // primitive

new String('foo') // object

When you call a String member function on a string primitive, it gets wrapped in a String object, which becomes the value of this within the function. (More on this behavior below.)

So, in removeExtension, this is a String object. On the other hand, the built-in function this.substr returns a primitive; that's just how it's defined. Thus, you see different things when you return this (String object) versus the result of this.substr (string primitive). If you want to return a string primitive version of the this object, just use this.toString.

You see the same wrapping behavior with any primitive, e.g., Numbers:

Number.prototype.returnThis = function() { return this; }

typeof 2;               // 'number'
typeof (2).returnThis() // 'object' (a Number object, specifically)

If you really want to know why this happens, it's in the ECMAScript spec:

10.4.3 Entering Function Code

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:

  1. If the function code is strict code, set the ThisBinding to thisArg.
  2. Else if thisArg is null or undefined, set the ThisBinding to the global object.
  3. Else if Type(thisArg) is not Object, set the ThisBinding to ToObject(thisArg).
  4. ....

Point #3 is the important on there: calling functions on primitive values (i.e., non-object) coerces them into their corresponding object form.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top