Question

I haven't really been able to find a clear and concise answer for this problem I'm having - I'm not even sure how to word it, exactly. But I'm building an object in Javascript (a "class", if you will) that I can reuse. I'm using the JSON approach to objects, as this is the only way I'm familiar with currently (I'm aware of the other methods, I just haven't been able to sit down and experiment with them yet).

So, here's an example of what I'm doing:

var Thing = {
    'property':{
        'one':5,
        'two':3
    },
    'action':(function(arg1, arg2){
        alert(arg1 + ' ' + arg2);
        return this.property.one + this.property.two;
    });
}

var t = Thing;
alert(t.action('x', 'y'));

As you can see, I've got my object, and it's got some nested properties. There's also a function, which is supposed to be able to manipulate said properties.

The problem I'm having is with scope. I'm tring to find a way to reference the object's properties within the function with out it being assumed that the properties BELONG to that function, because they don't. I've done it in the past, where I've just passed "this" as a parameter to the function and everything worked fine, but I'm willing to bet that isn't good practice. Also, as you can see, this function already takes some arguments anyway. Running this code give an error: "Uncaught TypeError: Cannot read property 'one' of undefined".

I'd like to keep my methods for building this object intact - it's something for work, and the object is already pretty large; but what I'm looking for is someway to "reach back up the tree" to get at those properties.

Was it helpful?

Solution

You are directly initializing object here. The JSON thing you are using is called object literal. As the name goes, its actually defining object literally.

Now lets come to your problem.

When you declare a function that has this.property.one the this keyword will be resolved on call time. And its usually the window object on browser. Read on more this. So it will never point to your Thing. What you can do is define a function for the class and add function to its prototype. Thats the classical way to implement oop in js.

function Thing(){
    this.property = {one: 5, two: 3}
}

Thing.prototype.action = function(arg1, arg2){
    alert(arg1 + ' ' + arg2);
    return this.property.one + this.property.two;
}

OTHER TIPS

This works:

var Thing = {
    'property':{
        'one':5,
        'two':3
    },
    'action':(function(arg1, arg2){
        alert(arg1 + ' ' + arg2);
        return this.property.one + this.property.two;
    }) // here don't put a ';'
}

var t = Thing;
alert(t.action('x', 'y'));

You should define a function.

var Thing = function(){
    this.property = {"one":5, "two":3};
    this.action = function(arg1, arg2){/*....*/}
}

var y = new Thing();
alert(y.action("x","y"));

This is the way i would be writing my classs.

As what another answer said though, it looks like you have a ; where it shouldnt be

I have two answers, one using your current JSON model, and the other in a more Javascript manner.

A.

When you define Thing like so.

var Thing = {
    'property':{
        'one':5,
        'two':3
    },
    'action':(function(arg1, arg2){
        alert(arg1 + ' ' + arg2);
        return this.property.one + this.property.two;
    })
}

you create a literal, meaning that each time you execute code such as

var t = Thing;

You pass by reference and do not create a new object in memory. Thus using more than one variable referring to Thing will create problems.

Additionally, your problem spews form the fact that the keyword this is found at runtime and usually refers to the browser window unless specified by the bind command. Keep in mind it must always be an object. The nature of a literal is such that it does not change the this variable in layman's terms.

B.

Now to address this problem in a better fashion. Instantiatable objects, or classes as you said, are created like any other function. However they are instantiated by the keyword new. In order to use their own reference, the this keyword represents the most derived instantiatable class in the current scope. Thus your example is better written as so

var Thing = function(){
    this.property = {};
    this.property.one = 5;
    this.property.two = 3;

    this.action = function Action(arg1, arg2){
        alert(arg1 + ' ' + arg2);
        return this.property.one + this.property.two;
    }
}

var t = new Thing();
alert(t.action('x', 'y'));

I hope that helps.

Furthermore

You said

I'm looking for is someway to "reach back up the tree"

While I'm not quite sure what you mean I'm inferring that if what I've said thus far doesn't help that you mean you have objects inside objects. For example, suppose you have a Student class that also contains a Schedule class. You may want to access student data from the schedule class. While this example is poor because by design, the Schedule instance shouldn't need to access Student data and if it needs to, it ought to be passed via function parameter, you can work through this as well.

function Student(age){
    this.age = age;
    this.schedule = new Schedule(this);
}

function Schedule(parent){
    this.getAge = function(){return parent.age;}
}

var s = new Student(16);
s.schedule.getAge();

You could simply pass the parent object into the instances of the children and accomplish the, backing up the tree as you said.

If you need a 'class' that generates different objects then I think you should look at shiplu.mokadd.im's answer. However maybe you need a module, which is kinda like a singleton:

var thing = (function() {
    var property = {
        one:5,
        two:3
    };

    function action(arg1, arg2){
        alert(arg1 + ' ' + arg2);
        return property.one + property.two;
    }

    return {
        action: action
    };
})();

alert(thing.action('x', 'y'));

What's going on here: use what's called a IIFE - Immediately-Invoked Function Expression. What it does here it assigns to the thing var whatever the IIFE returns (immidiately) - so in this case it returns an object with an action function.

Why is this useful? It creates a scope inside the IIFE which encapsulates whatever you're trying to make thing do. It also creates "private" functions and variables - you only return what you need - ex. the var property is not visible outside of thing and you cannot get a reference to thing.property.

Hope this was helpful!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top