Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does a string get mutilated when it becomes `this`?

Tags:

javascript

I discovered a peculiarity in JavaScript (or perhaps my browser's idea of it):

var s = "Hello, world";

function foo(arg)
{
    console.log(arg);
    console.log(this);
}

foo.call(s, s);

Running the above with Firebug console enabled, I get:

Hello, world
String { 0="H", 1="e", more...}

Why does the string automatically get turned into a weird object before becoming the this passed to foo ?

The reason I call it a weird object is because jQuery chokes on it. For example:

$.each(["one", "two", "three"], function(i, x) {
    $('<p></p>').text(x)   .appendTo('body'); // Works
    $('<p></p>').text(this).appendTo('body'); // Doesn't work
});
like image 890
Joey Adams Avatar asked Nov 30 '11 18:11

Joey Adams


2 Answers

this is coerced into an object, i.e. Object("test") is internally called.

(function() {
    return this;
}).call("test");

// returns same as `new String("test")` or `Object("test")`

if the method is a function in non-strict mode ... primitive values will be boxed*.

Note that using strict mode indeed does return the primitive value:

(function() {
    "use strict";
    return this;
}).call("test") === "test"; // true

* Boxing a value of a value allocates an object instance and copies the value into the new object.

like image 166
pimvdb Avatar answered Sep 21 '22 18:09

pimvdb


When using foo.call(s1, s2), you're invoking function foo, and setting the this keyword to s1. Since this has to be an object (so, not a primitive value), it's converted to a String object.

The individual characters of a string (created through s = "..." or s = String("...")) can be accessed through indexes, hence

String { 0="H", 1="e", more...}

function foo(arg)
{
    console.log(arg);   // passed as "Hello, world"
    console.log(this);  // passed as String("Hello, world")
    console.log(this instanceof String); //True
}


Code to demonstrate the indexes:
var i=0, s = "Hello, world";
for(; i<s.length; i++){
    console.log(i, s[i]);
}
/* Prints:
   0 H
   1 e
    ...
  */
 */
like image 40
Rob W Avatar answered Sep 21 '22 18:09

Rob W