简体   繁体   中英

Why does javascript change primitive types when passed into function.apply() or function.call()?

It seems that when using a primitive type (string, number) as the this subject of a function call (as the first argument to either function.call() or function apply()), the primitive type is promoted to its object equivalent (eg a string turns into a String).

To illustrate:

var f = function(x) { return [typeof(this), typeof(x)]; }  
var obj = '123'  
f.call(obj, obj)  
>>> ["object", "string"]  

That is, "this" becomes an object (it's a String object, I've checked) while the second argument to call becomes the first argument to the function "f", and remains a primitive string.

The objects are both "123", but subtle things don't work (for example, they are equal in terms of "==" but not in terms of "===").

I've noticed this behaviour in both chrome and firefox, so I'm assuming there's a specific reason for it. I've searched, but not found any explanation. I'd appreciate any explanation, hopefully with some sort of link to documentation explaining the rules around this and why it occurs.

This seems to be the correct behaviour.

http://bclary.com/2004/11/07/#a-15.3.4.4

Function.prototype.call - The called function is passed ToObject (thisArg) as the this value.

ToObject "converts its argument to a value of type Object according to the following":

String - Create a new String object whose [[value]] property is set to the value of the string.

First parameter in Javascript function call & Apply methods determine in which context the requested function has to be run. So this will always be a object

To illustrate this, checkout the below example

function totest() 
{
    this.ff  = function(x) {
        this.test(x);
    };

    this.test = function(x) {
        alert(x);
    }

}

function totest1() 
{   
 this.test = function(x) {
    alert(x);
}

}

function fun() 
{
     var obj = new totest();
     var obj1 = new totest1();
     obj.ff('hi');  //Runs fine without any problem
     obj.ff.call(obj, 'sam') ;  //Runs fine without any problem
     obj.ff.call(this, 'sam');  //throws an error
     obj.ff.call(obj1, 'sam');  //will be executed in the context of totest1

}

obj.ff.call(this, 'sam') throws an error. WHY

Because we specify the obj.ff method to be executed in the context of fun (or a window here) not in the context of totest.

obj.ff.call(obj1, 'sam') tells the call to execute the ff with in the context of totest1(), and it works since it got the method test.

so this has to be object.

And the remainning params in call method are real ones for the method to be executed. So they wil infer the type from the given value.

Hope you can understand now

Short and simple: The first parameter is turned into an object in case it is of a primitive type because, as you pointed out, it might be referred to by this in the called function. As this must refer to an object, the runtime environment makes sure there actually is an object to refer to. Think about how you would implement it, and you will probably come to the same conclusion. Good question.

PS: I appreciate Ramesh's answer, which is technically illustrative, but wanted to add an answer for the impatient reader.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM