1

I have this method of a JavaScript class that I've created:

resetRule() {
  let sheetRules = Array.from(this.sheet.rules);
  sheetRules.forEach(function(node, i) {
    if(node.name != undefined) {
      newRule.sheet.deleteRule(i);
    }
  });
}

when you instantiate a class, it essentially has to be set to a variable, like so:

const newRule = new NewRule(*params*);

and the methods/properties of said class can refer to the class object using this. like so:

this.method();
this.property;

What I'd like to know is: how does one refer back to the variable that instantiated the class within a function that is called by a method of said class?

To be even clearer: a function that is called within a method of a class alters the scope, which also means it alters the definition of this.. My question is: how do you get around this? How could you access the variable that instantiated the class when you are out the of scope of the methods within said class?


As I was composing this question, I realized that you can set the this value for a .forEach loop like this:

resetRule() {
  let sheetRules = Array.from(this.sheet.rules);
  sheetRules.forEach(function(node, i) {
    if(node.name != undefined) {
      this.sheet.deleteRule(i);
    }
  }, this);
}

However, the way this code works is something that--as far as I know--is just a benefit of the .forEach method, and I'd still like to know how it should be handled in general.

4castle
  • 32,613
  • 11
  • 69
  • 106
panrosmithe
  • 69
  • 10
  • 1
    "`the methods/properties of said class can refer to the class object using this`" — `this` refers to the local instance of that class – vol7ron Jul 30 '18 at 23:55
  • @vol7ron yeesss.. buuuuuut, if `this.method()` contains a function and you want to try to use `this` to refer to said 'instance' within that function, it doesn't work. Hence the question... – panrosmithe Jul 31 '18 at 00:00
  • I may need you to prove that – vol7ron Jul 31 '18 at 00:08
  • You can just do `let foo = this`, maybe this is what you need – Lux Jul 31 '18 at 00:08
  • @Lux would that be in the constructor? like: `class NewClass { constructor(a, b) { this.a = a; this.b = b; let foo = this } }`? or would it be just arbitrarily placed, like, between methods or something? – panrosmithe Jul 31 '18 at 00:11
  • How are you calling the method. Whenever you do `instance.method()`, `this` will be set to the class instance. – vol7ron Jul 31 '18 at 00:14

3 Answers3

1

Hopefully this should help you out, using your example.

class Rule {
  constructor(rules) {
    this.sheet = {
      rules: rules || []
    }
  }
  
  log(){
    console.log('rules:',this.sheet.rules)
  }
  
  resetRule() {
    let sheetRules = Array.from(this.sheet.rules);
    let self = this;       // <-- here you can capture the instance
    
    sheetRules.forEach(function(node, i) {
      self.log()           // <-- here you can use it in forEach   
      if (node.name != undefined)
        this.sheet.deleteRule(i);
    });
  }
}
const fooRule = new Rule(['foo'])
const barRule = new Rule(['bar'])

fooRule.resetRule()
barRule.resetRule()

fooRule.log()
barRule.log()

Your forEach works because as you discovered, you passed this as an argument for the thisArg parameter. However, if you didn't, you could have just as easily set it to a variable in the outer scope and used it in the block scope.

Generally creating a variable called self or that and setting it to this is helpful, especially for arrow functions, which set this to the encapsulating scope and not the instance object.

vol7ron
  • 40,809
  • 21
  • 119
  • 172
  • yup, this seems to be the general consensus. thank you sir. *to those who **marked as duplicate*** ya I figured that was gonna happen, but as I said, I didn't know how else to ask this question so... thanks for indirectly answering my question!! – panrosmithe Jul 31 '18 at 00:45
0

If I've not misunderstood you're looking for a way to retain your scope? You have a few options here.

The immediate answers would be to use Function.prototype.bind() or Function.prototype.call() to specify the context of this when invoking those methods.

Alternatively you could just make the scope of your this available where needed:

var MyClass = function () {
    // Here we bind the local scope to a variable that will give us context where necessary.
    // While it's not needed here, it can give context and set a pattern of reability through repitition.
    var vm = this;

    vm.methodA = function () {
        // We continue to set our 'vm' pointer variable when needed.
        var vm = this;

        globalMethod.then(function () {
            // We're able to retain context of our `this` through having scope of our 'vm' variable.
            vm.methodB();
        });
    };

    vm.methodB = function () {
        console.log('I did stuff!');
    };
};
Croot
  • 331
  • 1
  • 10
0

You could make a temporary variable called self or something which would allow you to use both the object containing "this" instance as well as within that anonymous function passed to forEach, this which will refer to sheetRules when you don't specify another variable to use as this

resetRule() {
  let sheetRules = Array.from(this.sheet.rules);
  let self = this;
  sheetRules.forEach(function(node, i) {
    if(node.name != undefined) {
    self.sheet.deleteRule(i);
    }
  });
}
techjeffharris
  • 392
  • 2
  • 13