3

I have to figure out, how to develop oop-javascript the right way. I read a lot about prototypes but the internet explained to me, I need it only, if I create an object a lot of times. But my SuperInterface exists only once. So I created it as an object:

var SuperInterface = {
    superaction: function () {
        alert(1);
    },
    actions: [{
        title: 'This is great',
        do_this: this.superaction
    }],
    init: function () {
        console.log(this.actions[0].title);
        this.actions[0].do_this();
    }
};
SuperInterface.init();

Running init() puts the title successfully to the console. But the alert is never called. I do not understand, why not? What should I change?

tjati
  • 5,761
  • 4
  • 41
  • 56
  • http://stackoverflow.com/questions/13441307/how-does-the-this-keyword-in-javascript-act-within-an-object-literal – Dr.Molle Aug 01 '15 at 21:08

3 Answers3

6

The value of this in the middle of that object initializer is not a reference to the object that is "under construction". There is no way to get such a reference during initialization since the object doesn't yet exist, and nor would you reference it with this. So you really can't initialize a property like that. You can however split it out into a separate statement:

var SuperInterface = {
    superaction: function () {
        alert(1);
    },
    actions: [{
        title: 'This is great',
        do_this: null;
    }],
    init: function () {
        console.log(this.actions[0].title);
        this.actions[0].do_this();
    }
};
SuperInterface.actions[0].do_this = SuperInterface.superaction;
1983
  • 5,882
  • 2
  • 27
  • 39
Pointy
  • 405,095
  • 59
  • 585
  • 614
  • _There is no way to get such a reference._ See my answer. – Vidul Aug 01 '15 at 21:32
  • @Vidul that does work in this case, but it's still true that there's no way to obtain a reference to an object in the middle of the object literal that describes it. – Pointy Aug 01 '15 at 22:40
  • I don't see how your statement relates to a possible fix. I also don't see how your statement _There is no way to get such a reference_ is not false. – Vidul Aug 01 '15 at 22:46
  • @Vidul Can you show me an example of how it's possible to obtain a reference to an object that's "under construction"? Your solution is a good one, but (A) it does not involve getting a reference to the object *while it is under construction*, and (B) it will stop working if the variable "SuperInterface" takes on a new value. There simply is no way to do it in JavaScript; the language does not provide a mechanism for it (at least, not in ES5). – Pointy Aug 01 '15 at 22:50
  • _(B) it will stop working if the variable "SuperInterface" takes on a new value_ ?! Please elaborate. – Vidul Aug 01 '15 at 22:54
  • Your code relies on the reference to "SuperInterface" in the anonymous function. That's not necessarily a bad thing, and I think your solution is a good one, but it's just a fact that if that variable changes, the meaning of your "do_this" wrapper function would change because it always refers to that variable. – Pointy Aug 01 '15 at 22:58
  • @Vidul [Here is a fork of your jsfiddle to illustrate what I mean.](https://jsfiddle.net/gv4fut62/) – Pointy Aug 01 '15 at 23:00
2

If you debug this code, you will find SuperInterface.actions[0].do_this is undefined The reason is quite obvious. At the time of evaluation of code.

  actions: [{
        title: 'This is great',
        do_this: this.superaction
    }]

this.superaction, here this points to the window object.

and in this window object superaction does'nt exits..

To make this work eventually you need to

var SuperInterface = {
    superaction: function () {
        alert(1);
    },
    actions: [{
        title: 'This is great',
        do_this: null
    }],
    init: function () {
        console.log(this.actions[0].title);
        this.actions[0].do_this();
    }
};
SuperInterface.actions[0].do_this = SuperInterface.superaction;
SuperInterface.init();

I hope you got the answer. Thanks

Kiba
  • 10,155
  • 6
  • 27
  • 31
  • 4
    `this` is never a reference to any part of any objects being initialized. It's whatever it is in the context of the outer `var` declaration. Object initializer expressions do not affect `this`, in other words. – Pointy Aug 01 '15 at 20:52
0

var SuperInterface = {
    superaction: function () {
        alert(1);
    },
    actions: [{
        title: 'This is great',
        do_this: function() {
          return SuperInterface.superaction();
        }
    }],
    init: function () {
        console.log(this.actions[0].title);
        this.actions[0].do_this();
    }
};
SuperInterface.init();

this in your case refers to the literal object inside the array actions - it does not contain the method superaction.

Vidul
  • 10,128
  • 2
  • 18
  • 20
  • I'm guessing the downvote is for your final remark. `this` refers to the global object. – 1983 Aug 01 '15 at 21:41
  • @KingMob Is this so? Test it: put `console.log(this);` in `do_this`. – Vidul Aug 01 '15 at 21:47
  • 2
    In the original Q. it is the global object (assuming no other context). – 1983 Aug 01 '15 at 21:53
  • @KingMob I don't get your point. _Pointy: There is no way to get such a reference._ Wrong - there is a way, that is my point. – Vidul Aug 01 '15 at 22:37
  • You're saying that `this` in `do_this: this.superaction` in the Q. refers to `SuperInterface.actions[0]`, which is wrong. – 1983 Aug 01 '15 at 22:45
  • @Vidul Perhaps I am not explaining the issue clearly. In an object literal, *without reference to any symbols outside the object*, there is no way to obtain a reference to the object being constructed. – Pointy Aug 01 '15 at 22:53
  • **'In the original Q.'** By invoking a method you're changing the `this` value. – 1983 Aug 01 '15 at 22:54
  • 2
    The value of `this` is **never** affected by an object literal expression. The **only** thing that sets `this` is function invocation or entry into a "global" scope. An object literal does not change `this`. – Pointy Aug 01 '15 at 22:54
  • 2
    In your JSFiddle, the function is called *after* the object has been constructed. The value of `this` is what it is because of that function call being made. – Pointy Aug 01 '15 at 22:56
  • @Pointy Obviously we are mixing the topics. I don't deny your statements except this one: `There is no way to get such a reference`. – Vidul Aug 01 '15 at 23:02
  • 2
    @Vidul it's a hard concept to communicate. Your anonymous function can get a reference, that is true - but it gets the reference **after** the object has been constructed. You obviously know JavaScript so that seems really obvious probably, but this question comes up a lot on StackOverflow. People expect `this` to refer to the object being built, which is not crazy or dumb but it's just not how JavaScript works. – Pointy Aug 01 '15 at 23:05
  • @Pointy Everything seems hard if you don't know the concrete answer to a question. – Vidul Aug 01 '15 at 23:24