Any way to modify 'this' in JavaScript?

后端 未结 4 1382
伪装坚强ぢ
伪装坚强ぢ 2021-01-06 08:56

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?

相关标签:
4条回答
  • 2021-01-06 09:19

    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.

    0 讨论(0)
  • 2021-01-06 09:20

    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();
    
    })();
    
    0 讨论(0)
  • 2021-01-06 09:24

    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/

    0 讨论(0)
  • 2021-01-06 09:40

    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.

    0 讨论(0)
提交回复
热议问题