6

My typical JS class structure looks like this:

MyClass = function(args)
{
   this.myProp1 = undefined;
   this.myProp2 = args[0];
   //...more member data 

   this.foo = function()
   {
       return this.myProp1 + this.myProp2; //<- the problem.
   }
   //...more member functions
}

//if MyClass extends a superclass, add the following...
MyClass.prototype = Object.create(MySuperClass.prototype);
MyClass.prototype.constructor = MyClass;

...My ongoing annoyance with JS is that I seem to have to use this continuously in member functions in order to access the properties of the very same object to which those functions belong. In several other languages e.g. C# & Java, this may be safely omitted when member functions are working with member data in the same class / instance. (I realise that JS is structured fundamentally differently due to it being designed as a prototypal rather than a hierarchical inheritance language.)

To put the question another way: Is there any way to make the unspecified scope NOT point to window, but rather to the current, local value of this?

P.S. I am guessing this is a language limitation, but thought I'd check again anyway.

Engineer
  • 8,529
  • 7
  • 65
  • 105
  • 2
    You could use `with`, but that is really ugly. Alternatively, you could store the properties in the local scope instead of assigning it to `this`. – Rob W Jul 27 '14 at 15:35
  • Hi @RobW, Yep caching as local variables is what I usually do, but it can become onerous quickly in a complex application. Also, I knew of `with` from ActionScript, but my understanding from those days was that it can be terribly slow. Maybe I should look at how it performs under modern JS engines. – Engineer Jul 27 '14 at 15:36
  • 2
    FWIW, the keyword to dig into this in the specification is *object environment record*: http://es5.github.io/#x10.2.1.2 – Felix Kling Jul 27 '14 at 15:46
  • Why would you define foo in the constructor function and not on it's prototype? Code as is doesn't seem to be needing every instance of MyClass to have it's own foo method. – HMR Jul 27 '14 at 16:50
  • In your answer you mention the module pattern and Douglass. I am not a big fan of his ideas about constructor functions and have yet to see a presentation or article where he does "classical inheritance" correctly. Instead of fixing the faulty code he blames it on JS. The module pattern does not allow you to have privileged functions to access your private variables so can't put them on the prototype. At the end of this answer http://stackoverflow.com/a/16063711/1641941 is a link to a pattern that can be used to simulate protected. Still doesn't solve your `this` problem though. – HMR Jul 27 '14 at 17:02

5 Answers5

3

In several other languages e.g. C# & Java, this may be safely omitted when member functions are working with member data in the same class / instance. (I realise that JS is structured fundamentally differently due to it being designed as a prototypal rather than a hierarchical inheritance language.)

It's not about the inheritance chain, which is rather static in js as well. It's about JS being a dynamic language, with the global scope being able to add new variables at will, and objects being amendable with arbitrary properties.

So it's just not really possible to make an identifier dynamically resolve to either a local variable or an object property, and we want to distinguish explicitly between them every time by using property accessors for property access.

Is there any way to make the unspecified scope NOT point to window, but rather to the current, local value of this?

The "unspecified scope" is the local scope, which is statically determined and optimized. To make it point to an object (and fall back to variables if the property is not found), you can use the with statement. However, due to this ambiguity it's not only slow, but also considered bad practise - the lookup (of variables) can be influenced by non-local code (that interacts with the instances) which breaks encapsulation and is a maintainability issue.

My typical JS class structure …

Of course you could also change that, and use local variables that are accessed via closure as members instead (see also Javascript: Do I need to put this.var for every variable in an object?). This solves the problems with this, but is also a bit slower (though probably still faster than with).

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
2

There is a keyword which partially does what you want: with but it is highly not recommended to use it, because ambiguous in some cases.

If you access a non existing member it will fallback to the window object. So what you could do is declare all the properties you are going to use later and then declare a with statement.

If I had the choice you have, I'd probably change my mind about skipping this or if you can, use another language.

axelduch
  • 10,769
  • 2
  • 31
  • 50
2

I am not sure is it Language limitation or something else, but the pattern you have used for Class and member function creations, will not help to achieve that you want to.

Why do not you try Module Pattern like this ?

CalcModule = (function(){
    var add = function(a, b) {
        return a + b;
    };

    var sub = function(a, b) {
        return a - b;
    };

    var _privateCalculation = function(){
    };

    return {
            "add" : add,
            "sub" : sub
    };
});

Here you get a control to mimic private members by not having them in return object.

Update : I am not sure about extension of Module pattern classes.

Update : Added var for function declarations

Alexis Tyler
  • 1,394
  • 6
  • 30
  • 48
Akash Saikia
  • 452
  • 6
  • 19
0

It's probably best to avoid using a with statement because the presence of a with statement disables optimization. Also, a with statement cannot be used in strict mode. See ECMA 262 §12.10.1: "Strict mode code may not include a WithStatement. The occurrence of a WithStatement in such a context is treated as a SyntaxError."

One option is to use a syntax extension that expands to a property access. For instance, in CoffeeScript 0.3.2, @property was added as shorthand for this.property.

If you don't want to use CoffeeScript, you can create your own macro with sweet.js. Here is an example of a macro that adds the @property shorthand feature:

macro @ {
    case { _ $x:ident } => { return #{ this.$x }; }
    case { _ $x } => { return #{ this[$x] }; }
}

function Person(name) {
    @name = name;
}

var person = new Person("Johnny Appleseed");
alert(person.name);

The sweet.js compiler, sjs, generates:

function Person$630(name$632) {
    this.name = name$632;
}
var person$631 = new Person$630('Johnny Appleseed');
alert(person$631.name);
  • Thanks. Given Mozilla's recommendations and my own experience of `with`'s performance (still a real issue), `with` simply isn't in the picture. For the framework I'm writing, I'll keep to pure JS and have to deal with `this` if I must; maybe the coffeescript approach will help someone, though. – Engineer Jul 27 '14 at 17:41
-1

Adding my own answer here for posterity, because at some stage, if I'm stuck between being forced to (1) prepend this and (2) using the terrifying with, it might be useful to have a (3)rd solution.

Let's assume we do not access any member data directly; instead we have getter and setter methods for each data property.

In this case, it's possible to use the private concept as discussed by Doug Crockford:

MyClass = function()
{
   var prop = undefined;
   this.getProp() {return prop;}
   this.setProp(value) {prop = value;}

   //now in standard, non-getter and -setter methods, we can do...
   this.foo = function()
   {
       return prop + prop; //<- no problem: no more 'this'
   }
}

And a (4)th solution, less safe but also less verbose:

MyClass = function()
{
   var prop = this.prop = undefined; //this.prop for read only! (unsafe)
   this.setProp(value) {prop = this.prop = value;}

   //now in standard, non-getter and -setter methods, we can do...
   this.foo = function()
   {
       return prop + prop; //<- no problem: no more 'this'
   }
}

In (4), we need only setters, reducing verbosity greatly.

With few methods containing a lot of logic, this works well. With many smaller methods, its sheer size (all those accessor methods) end up outweighing the benefit of avoiding this every time we access a local member. Still -- it does lead to cleaner in-function logic.

Engineer
  • 8,529
  • 7
  • 65
  • 105
  • 1
    Why maintain both the public `this.prop` and the private `prop`? Choose one or the other depending upon the intended design, but not both. – jfriend00 Jul 27 '14 at 15:53
  • @jfriend00 Did you read & understand the question? I added a method above so you can see the reasoning behind it. – Engineer Jul 27 '14 at 15:53
  • Yes, I understood the question. So, why are you even including `this.prop` in your example. It is not needed. You already have `getProp()` and `setProp()`to get an set the property - no public access directly to the property is needed so I see no reason to double maintain a value. Also, you are no longer using the prototype which has some consequences. – jfriend00 Jul 27 '14 at 15:55
  • The real answer is that you just need to "get used to the way code is written in Javascript" and stop wishing it worked like other languages. Then, you will be comfortable writing JS the way it was intended to be written and it will eventually feel natural to you. I know it is common to start with a base of understanding and conveniences from other languages, but once you really get to know JS, you will find it has structures and conveniences that C# and Java do not and you will come to appreciate those for what they let you do. JS is different. Learn and embrace the differences. – jfriend00 Jul 27 '14 at 15:58
  • 1
    This seems good for a single method or member, but what if you want to access other member variables in the same way? Are you going to make a closure for each and every member variable given in the class. Is not this what a module pattern does? :-) – Akash Saikia Jul 27 '14 at 16:00
  • @AkashSaikia Yes, spot on. It could quickly make classes very heavy, as noted in my final paragraph. The tipping point is where you have many small methods vs a few, larger methods (where this approach becomes viable). – Engineer Jul 27 '14 at 16:02
  • 1
    Even with your edit, there is no reason for `this.prop` to exist. In fact, there are good reasons for it not to exist, because if someone sets it directly from the outside world, it will disagree with the local `prop`. – jfriend00 Jul 27 '14 at 16:02
  • @jfriend00: It seems to be there for getting only. However, I'd recommend to use a [setter and getter property](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) instead, and never use an extra `setX` method without a respective `getX` method – Bergi Jul 27 '14 at 16:32