0

I am getting my feet wet with ES6 and implementing design patterns in Javascript for live projects. I have the following example snippet of code which throws an error saying that the this keyword evaluates to undefined:

export let LifecycleFactoryObj = (() => {
  this.myCollection = new WeakSet();
  //.... More here
  this.add = function (opts) {
    let tempObject = new MyCollection(opts);
    this.myCollection.add(tempObject);
    if (this.myCollection.has(tempObject)) {
      return tempObject;
     }
    return null;
  };
})();

The error that is thrown is:

undefined.lifecycles = new WeakSet(); ^ TypeError: Cannot set property 'lifecycles' of undefined

Looks like this inside the IIFE is being evaluated to undefined but I can't seem to trace why. I thought ES6 had scoped the this keyword correctly when using let for variable instantiation.

Thanks!

Tom Pennetta
  • 482
  • 7
  • 25
  • So what did you expect `this` to be? Yes, it's not scoped to the function. – Bergi Aug 17 '15 at 19:30
  • In Javascript everything is an object. Functions both named and anonymous. For people of OO backgrounds it can be a bit confusing to fully understand the this keyword, its scope, closures, etc. If this is an anonymous function being assigned to a variable, I would think this would refer to the function object, which the variable has a reference to. – Tom Pennetta Aug 17 '15 at 19:51
  • Well, for one you're not assigning the anonymous function to the variable but the result from calling it (which is `undefined` btw). And no, [the value of `this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) is determined by the function call, not by some unrelated variable. And it hardly ever points to the called function. – Bergi Aug 17 '15 at 20:05
  • 1
    Makes sense just learning curve is all. But this makes sense and the MDN article with its reference is very helpful thanks. – Tom Pennetta Aug 17 '15 at 20:28
  • Related: [Compiling ES6 arrow functions to Es5 using Babel.js](http://stackoverflow.com/q/30702553/218196) – Felix Kling Aug 17 '15 at 22:16

1 Answers1

1

this isn't defined in ES6 if you don't use a constructor or don't have an object already; you'll need to use either the traditional syntax (function ClassName) or the new syntax (class ClassName) to create a constructor, and then call that constructor.

In your case, it doesn't seem like a full-blown class is necessary, so try using a normal object:

export let LifecycleFactoryObj = {
    myCollection: new WeakSet(),
    //.... More here
    add: function(opts) {
        let tempObject = new MyCollection(opts);
        this.myCollection.add(tempObject);
        if (this.myCollection.has(tempObject)) {
            return tempObject;
        }
        return null;
    }
};
Kevin Ji
  • 10,479
  • 4
  • 40
  • 63
  • 1
    *"this isn't defined in ES6 if you don't use a constructor or don't have an object already;"* Well, I can do `foo.call(bar)` to set `this` inside `foo` to `bar` (assuming it's a regular function). – Felix Kling Aug 17 '15 at 22:15
  • That's true. By default though functions have no `this` associated without the methods I mentioned. – Kevin Ji Aug 17 '15 at 22:26
  • @mc10 `let x = {a:1, b:function() { return this.a; }}; x.b(); //=> 1` – Mulan Aug 18 '15 at 07:43