f



when string is not a string

Curious javascript sample.

Consider the following code:

var s = "asd"
var f = function() { return typeof(this) }

An expression typeof(s) returns true (as it is expected), but
f.call(s) returns false!

To make matters worse consider the following snippet:

var s = "asd"
var f = function() { return this instanceof String }

An expression f.call(s) returns true, but (s instanceof String)
returns false!


The question is why call transforms this to an object? Is it made for
unification, e.g. to make this iterable using 'for (var i in this)'
loop?

It is also unclear why string literal in fact is not an instance of
String in ("asd" instanceof String) expression but it does a string
in  call/apply method invokations.

I see this might be a kind of boxing/unboxing in .NET, but I see no
reason why language designers made such a choice.
0
avshabanov (22)
5/12/2010 10:18:25 PM
comp.lang.javascript 38370 articles. 2 followers. javascript4 (1315) is leader. Post Follow

7 Replies
1434 Views

Similar Articles

[PageSpeed] 47

Alex Shabanov wrote:

> Curious javascript sample.

There is no "javascript": <http://PointedEars.de/es-matrix>
 
> Consider the following code:
> 
> var s = "asd"
> var f = function() { return typeof(this) }
> 
> An expression typeof(s) returns true

No, it does not.  The expression is supposed to evaluate to and actually 
evaluates to "string" in JavaScript 1.8.2, but in this context it evaluates 
to "object" in JavaScript 1.8.2.  BTW, `typeof' is an operator, so you 
should lose the parentheses.

> (as it is expected),

Check your assumptions.

> but f.call(s) returns false!

No, it does not.  Because `this' always refers to an object, that call 
returns "object".
 
> To make matters worse consider the following snippet:
> 
> var s = "asd"
> var f = function() { return this instanceof String }
> 
> An expression f.call(s) returns true,

As expected, see above.  The primitive string value that is used as the 
thisArg by Function.prototype.call() is converted to an object, a String 
instance, when execution enters the function context [ES5, 10.4.3].

> but (s instanceof String) returns false!

Yes, because `s' stores a primitive string value, not a reference to a 
String instance.

> The question is why call transforms this to an object?

It does not do that.

> Is it made for unification, e.g. to make this iterable using 'for (var i
> in this)' loop?

You are jumping to conclusions.
 
> I see this might be a kind of boxing/unboxing in .NET, but I see no
> reason why language designers made such a choice.

While the first result you observed could be a bug in your ECMAScript 
implementation, it is more likely that you don't know what you are doing.


PointedEars
-- 
    realism:    HTML 4.01 Strict
    evangelism: XHTML 1.0 Strict
    madness:    XHTML 1.1 as application/xhtml+xml
                                                    -- Bjoern Hoehrmann
0
Thomas
5/12/2010 10:37:39 PM
On 13/05/10 00:18, Alex Shabanov wrote:
> Curious javascript sample.
> 
> Consider the following code:
> 
> var s = "asd"
> var f = function() { return typeof(this) }
> 
> An expression typeof(s) returns true (as it is expected), but
> f.call(s) returns false!

In ECMAScript 3, |this| is always an object. call() and apply() will
convert anything passed as the first argument (the "thisArg") to its
object form, except null and undefined:

| If thisArg is null or undefined, the called function is passed the
| global object as the this value. Otherwise, the called function is
| passed ToObject(thisArg) as the this value.
(ECMA-262, 3rd edition, 15.3.4.4)

The ToObject operation is defined in section 9.9.

> To make matters worse consider the following snippet:
> 
> var s = "asd"
> var f = function() { return this instanceof String }
> 
> An expression f.call(s) returns true, but (s instanceof String)
> returns false!

s is a string primitive (typof s == "string"), and |this| is a String
object (typeof this == "object"). The conversion happened in call().

> It is also unclear why string literal in fact is not an instance of
> String in ("asd" instanceof String) expression but it does a string
> in  call/apply method invokations.

The "asd" literal is not an object, so it can't be an instance of
anything at all. There are cases where intermediary objects are
automatically created for primitive types (for example when you read
"asd".length), but instanceof is not one of these cases.

> I see this might be a kind of boxing/unboxing in .NET, but I see no
> reason why language designers made such a choice.

For the lulz? No, sorry, I don't know; you'd have to ask them.
Performance or memory considerations could have played a role (like they
did in Java). Come to think of it, maybe the similarity to Java's
strings and Strings was intended, but I'm only guessing here.


-- 
stefan
0
Stefan
5/12/2010 10:43:20 PM
On May 13, 2:18=A0am, Alex Shabanov <avshaba...@gmail.com> wrote:
> The question is why call transforms this to an object?

Because you wanted it. call() sets the context of its first argument,
and it cannot be primitive value (string primitive in your case).
Javascript was originally made in the way to understand bad coding as
long as it's possible, with an armee of non-professional programmers
in mind. So instead of throwing illegal argument error, it wraps
string primitive into String object and works with it. Obviously it
doesn't affect the s string itself, it remains string primitive.
Same Javascript will do with other primitive, i.e.:

var n =3D 2;

function f() {
 window.alert(this instanceof Number);
}


f.call(n); // alerts true

window.alert(typeof n); // number


> It is also unclear why string literal in fact is not an instance of
> String in ("asd" instanceof String) expression but it does a string
> in =A0call/apply method invocations.

Again, in Javascript there are string primitives and string objects.
By default string literals create string primitives:
 var s =3D "abc";
To make a string object one needs to use constructor:
 var s =3D new String("abc");
but it has little practical sense: Javascript will "upcast" primitives
if needed and downcast when not needed anymore. Say
 var len =3D s.length
it upcast and downcast s to get the length value - because string
primitive has no properties or methods, only String object does.




0
VK
5/12/2010 10:51:43 PM
Stefan Weiss wrote:

> Alex Shabanov wrote:
>> var s = "asd"
>> var f = function() { return typeof(this) }
>> 
>> An expression typeof(s) returns true (as it is expected), but
>> f.call(s) returns false!
> 
> In ECMAScript 3, |this| is always an object. call() and apply() will
> convert anything passed as the first argument (the "thisArg") to its
> object form, except null and undefined:
> 
> | If thisArg is null or undefined, the called function is passed the
> | global object as the this value. Otherwise, the called function is
> | passed ToObject(thisArg) as the this value.
> (ECMA-262, 3rd edition, 15.3.4.4)

ES5 specifies it differently, but to the same effect.
 
>> To make matters worse consider the following snippet:
>> 
>> var s = "asd"
>> var f = function() { return this instanceof String }
>> 
>> An expression f.call(s) returns true, but (s instanceof String)
>> returns false!
> 
> s is a string primitive (typof s == "string"), and |this| is a String
> object (typeof this == "object").

Yes.

> The conversion happened in call().

Depends.


PointedEars
-- 
Use any version of Microsoft Frontpage to create your site.
(This won't prevent people from viewing your source, but no one
will want to steal it.)
  -- from <http://www.vortex-webdesign.com/help/hidesource.htm> (404-comp.)
0
Thomas
5/12/2010 10:54:12 PM
VK wrote:

> Alex Shabanov wrote:
>> The question is why call transforms this to an object?
> 
> Because you wanted it. call() sets the context of its first argument,

Nonsense.

> and it cannot be primitive value (string primitive in your case).

Correct.

> Javascript was originally made in the way to understand bad coding as
> long as it's possible, with an armee of non-professional programmers
> in mind.

Nonsense.

> So instead of throwing illegal argument error, it wraps
> string primitive into String object and works with it. Obviously it
> doesn't affect the s string itself, it remains string primitive.

Correct.

>> It is also unclear why string literal in fact is not an instance of
>> String in ("asd" instanceof String) expression but it does a string
>> in  call/apply method invocations.
> 
> Again, in Javascript there are string primitives and string objects.
> By default string literals create string primitives:
>  var s = "abc";
> To make a string object one needs to use constructor:
>  var s = new String("abc");
> but it has little practical sense: Javascript will "upcast" primitives
> if needed and downcast when not needed anymore. Say
>  var len = s.length
> it upcast and downcast s to get the length value - because string
> primitive has no properties or methods, only String object does.

True, except of "upcast" and "downcast" which are yet again products of your 
vivid imagination, to put it politely.


PointedEars
-- 
var bugRiddenCrashPronePieceOfJunk = (
    navigator.userAgent.indexOf('MSIE 5') != -1
    && navigator.userAgent.indexOf('Mac') != -1
)  // Plone, register_function.js:16
0
Thomas
5/12/2010 11:01:51 PM
On May 13, 3:01=A0am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
> ...

Thanks all who answered. It is clear now.
0
Alex
5/13/2010 6:27:28 AM
Thomas 'PointedEars' Lahn <PointedEars@web.de> writes:

> Stefan Weiss wrote:
>
>> In ECMAScript 3, |this| is always an object. call() and apply() will
>> convert anything passed as the first argument (the "thisArg") to its
>> object form, except null and undefined:
>> 
>> | If thisArg is null or undefined, the called function is passed the
>> | global object as the this value. Otherwise, the called function is
>> | passed ToObject(thisArg) as the this value.
>> (ECMA-262, 3rd edition, 15.3.4.4)
>
> ES5 specifies it differently, but to the same effect.

.... execept in strict mode functions, where the ThisBinding of function 
need not be an object. (10.4.3, step 1).

/L
-- 
Lasse Reichstein Holst Nielsen
 'Javascript frameworks is a disruptive technology'
  
0
Lasse
5/13/2010 10:17:45 AM
Reply: