Swiffy
Swiffy

Reputation: 4693

Any way to modify 'this' in JavaScript?

I found this answer: How to modify "this" in javascript

But I did not like it. Surely there must be a way to somehow modify this?

Here is an example:

(function()
{

    var a = function(v)
    {
        v += 10;

        a = function()
        {
            console.log(this);
            this += 5; // How to "unlock" 'this'?
            console.log(this);
        }.bind(v)

        //a();
    }

    a(0);
    a();

})();

Fiddle: https://jsfiddle.net/ahvonenj/mz19aku6/

If you comment out the this += 5 part, the console says that this is Number {[[PrimitiveValue]]: 10}. So I do not see a reason why a Number (PrimitiveValue) type could not be increased by 5 and printed out. What am I missing here?

Is there a way to "break out" of the engine thinking this as this and somehow forcefully convert this to what it says it is - Number in this case?

Maybe by somehow making a function that accepts a to-be-converted this as an argument and returns a new function which has the supplied this rebound with bind?

Note: I am not looking for doing anything practical with a possible solution. I am just curious from a technical standpoint or something.

Edit: So a user named Oriol told me that this is not actually a Number object with a value of 10, but Instead a Number literal. This apparently means that this += 5 is almost the same as writing 10 += 5 in this case. I tried checking out out like so:

(function()
{

    var a = function(v)
    {
        v += 10;

        a = function()
        {
            console.log(this);
            var p = this + 5; // How to "unlock" 'this'?
            console.log(p);
        }.bind(v)

        //a();
    }

    a(0);
    a();

})();

So var p = this + 5 is now basically the same as writing var p = 10 + 5, which is what we expected.

Upvotes: 5

Views: 2989

Answers (4)

user663031
user663031

Reputation:

You can think of this as an implicit, immutable, value accompanying a function call.

There are a number of ways it can be set, the most common being that a call of the form o.f() sets this to o within f. Of course, this can also be set with call and apply and bind, and in other ways as well.

this is not like other function parameters. If were a normal parameter, its value could in theory be changed. Instead, it represents a value, a sort of lexical placeholder for the value of this. In other words, if I call

f.call(5)

and then write

function f() { console.log(this); }

You can think of the this as being lexically replaced by the value 5. So if I tried to write

function() { this += 5; }

you can think of this as being the equivalent of

function() { 5 += 5; }

which is obvious nonsense. I cannot replace the value 5 with something else. By the same token, if I said

o = {
  f: function() { this = o2; }
};

and then call o.f(), the function is essentially rewritten as

function() { { f: ... } = o2; }

which is equal nonsense. I cannot re-assign the value of an object.

Since this is a value, not a parameter, it cannot be assigned to or changed. It is not a valid left-hand-side for an assignment, any more than 42 is. We cannot change the value of the value named 42. We cannot change the value of the value named this.

The reason for this is that is the specification. In theory, one can imagine a version of JavaScript where this was mutable. There is no definitive reason why this should not be possible. After all, no matter where it comes from, within the function it is simply a value. It would be confusing, and could result in unexpected behavior, but there is no reason why it could not work.

The primary reason this is not supported is simply that that is not how the language is defined. If your question is "why is the language defined that way", then that is something for language historians to answer. However, one can imagine good reasons for this, involving intuitive code behavior.

Consider the following code:

o = {
  f: function() { 
    this.doSomething();
    this = o2;
    this.doSomething();
};

It is going to be extremely hard for normal human beings to understand such code. The same two this.doSomething() calls do two different things due to the intervening change to this. This alone is a more than adequate reason to prohibit changing the value of this. All the more so since there is no logical reason for needing to do this, since I can replace the last two lines with a simple o2.doSomething().

Just to be clear, of course when we talk about "changing this", even if we could do that, which we can't, we couldn't possibly mean somehow changing the outside value this refers to. We all know that in the following case:

function a(x) { x = 2; }
var y = 1;
a(y);

The change to x within a() is purely local, and can't possibly affect y. The same thing would apply equally to this of course.

One more note on objects wrapping primitives. We know we can write

o5 = Object(5);

to get an object wrapping the number 5. Now I can define a method on this object, as in

o5.f = function() { console.log(this); };

and calling o5.f() will log

Number {[[PrimitiveValue]]: 5}

So since this object "is" a number, certainly in this case I should be able to say

o5.f = function() { this++; };

But no. this is not the number 5; it's an object wrapping 5. Those are two very different things. The function above is essentially equivalent to saying

o5.f = function() { Object(5)++; }

which yields

Uncaught ReferenceError: Invalid left-hand side expression in postfix operation

Now I can do arithmetic on the object, such as Object(5) + 1, because JS will coerce the object to its underlying primitive before adding one. But I cannot re-assign to this object any more than any other. And I cannot modify the primitive number underlying the object. Once the wrapper object is created, the primitive value underlying it is locked in forever.

So the answer to your question is "no, there is no way to change this". Which is not to say there are not other ways to do other things to accomplish whatever it is you want to accomplish.

Upvotes: 4

David Haim
David Haim

Reputation: 26496

I don't know any language that allows you to alter this.

you might want to think of this as an address:
my house "sits" on Sesame street 10. of course, I can invite designers who can change who my Sesame-street-10-house looks like, but can I suddenly make Sesame street 10 turn into Sesame street 15? of course not. I can't just rip an entire piece of land and pass it 5 houses ahead.

going back to programing context, this (eventually) is interpreted to the memory block your object sits in. you can change that object which sits on the specified memory block, but you can't just change the block address.

Upvotes: 2

Raju Bera
Raju Bera

Reputation: 1018

Actually the problem here is that when you binding the function to a number then the this is getting changed to number and now when you are doing the assignment operation this += 5; the left hand side is not a variable where we can store the new value as its a primitive number instance. so to overcome that what you can do is you can store the this value in another variable say me and then do the operation as following:

(function() {

    var a = function(v) {
        v += 10;

        a = function() {
            var me = this;
            console.log(this); //logs Number {[[PrimitiveValue]]: 10}
            me += 5; 
            console.log(me); //logs 15
        }.bind(v)

        //a();
    }

    a(0);
    a();

})();

Upvotes: 2

Tarwirdur Turon
Tarwirdur Turon

Reputation: 781

See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures

Simple types (except objects and arrays) is immutable. You can't modify it and save in source variable.

function foo() {
    this.val+=10;
}

a=function(obj) {
    a=foo.bind(obj);
}

But you can wrap it into object. See: http://jsfiddle.net/5dhm8fsn/

Upvotes: 1

Related Questions