0

I have this code that works perfectly well on its own :

var Person = {
    getName: function() {
        alert("Johnny");
    }
};

var myContext = "Person";
var theCodeToExecute = myContext + ".getName()";
var theFunctionItself = new Function(theCodeToExecute);
theFunctionItself(); 

But when I put it inside jQuery, it stops working.

$(document).ready(function() {
    //Where the code should be.
});

I'm aware that very similar questions have been answered, but none of them fixed that precise problem.

EDIT :

Thanks everyone for the answers. I guess I narrowed down my problem so much that I made my intentions very unclear. Here's a clearer version of what i'm trying to achieve :

var Road = {
       House: function(color, size, neighbor){
          this.color = color;
          this.size = size;
          this.neighbor = neighbor;
       }
};

Road.House.prototype.getSize = function() {
    alert(this.size);
};

Road.House.prototype.getNeighborSize = function() {
    var theNeighbor = this.neighbor;
    var codeToExecute = theNeighbor + ".getSize()";
    var tmpFunc = new Function(codeToExecute);
    tmpFunc();    //this only works when outside of jQuery.    
};

var house1 = new Road.House("blue", "small", "house2");

var house2 = new Road.House("red", "huge", "house3");

house1.getNeighborSize(); //this successfully returns "huge" when outside of jQuery.

Again, this works perfectly well on its own but doesn't work within jQuery, and I need it to work within jQuery because the final version of my functions will use a lot of jQuery code. Thanks again!

LAST EDIT :

Thanks Felix for your excellent help. There seems to be one final problem. I can only get the size of a neighbor if the neighbor is declared BEFORE the house I'm querying.

var house1 = new Road.House("red", "big", house2);
var house2 = new Road.House("blue", "huge", house3);
var house4 = new Road.House("blue", "small", house4);
var house3 = new Road.House("blue", "little", house1);

house1.getNeighborSize(); //this doesn't work.

house3.getNeighborSize(); //this works

Thanks again!!

7
  • You might want to post a jsFiddle to illustrate the issue. Commented Dec 13, 2014 at 21:10
  • Did you add jquery.js file ? check the errors on the console Commented Dec 13, 2014 at 21:11
  • why do you want to put it in jQuery $(document).ready(function() ? You can just use window.onload = function() { ... code ... } Commented Dec 13, 2014 at 21:12
  • The Console says : "ReferenceError: Person is not defined". Commented Dec 13, 2014 at 21:15
  • Make sure you are defining Person within the $(document).ready function, otherwise it will be out of scope. Commented Dec 13, 2014 at 21:22

2 Answers 2

4

When you create a function with new Function, it will be created in global scope. I.e. it does not have access to the variables you created inside the ready callback.

// global scope

$(document).ready(function() {

   // ready callback scope    

});

Citing the big yellow box from MDN here:

Note: Functions created with the Function constructor do not create closures to their creation contexts; they always are created in the global scope. When running them, they will only be able to access their own local variables and global ones, not the ones from the scope in which the Function constructor was called. This is different from using eval with code for a function expression.

Solutions:

  1. Create Person in global scope.
  2. Use eval instead of new Function.

and the best of all:

  1. Don't evaluate code dynamically. You could just write Person.getName() directly.

Even if you think you'd have to evaluate code, you probably don't, but we can't help you find alternatives if you don't explain what you are really trying to achieve.


Well, the actualy to solution to your problem is not to try to refer to variables dynamically, but pass a reference to the neighbor to the constructor:

var house2 = new Road.House("red", "huge");
var house1 = new Road.House("red", "huge", house2);

Then the function would look like

Road.House.prototype.getNeighborSize = function() {
    if (this.neighbor) {
        this.neighbor.getSize();
    } 
};

If you can't pass a reference to the neighbor at construction time, you can create a setter:

Road.House.prototype.setNeighbor = function(neighbor) {
    this.neighbor = neighbor;
};
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you for the answer. I'll edit my question to say what I'm really trying to achieve.
Thank you for the update! I'm checking it right now.
Ok, this is strange, your new code works inside jQuery, but it only works if house2 doesn't have a neighbor.
The problem with passing the neighbor in the constructor is that the neighbor has to already exist before you can create another house. If you use a setter instead, you can create all houses independently and set up their relation afterwards.
Thanks again for your help, Felix! I'm using a setter now and everything works.
|
0

Alright, there are a few errors here if you're trying to invoke a method. You should avoid dynamically evaluating Javascript like that, as Felix mentioned. First off I'll start with the corrected code, assuming you just wanted to invoke the getName method.

$(document).ready(function() {

    var Person = {
    getName: function() {
        alert("Johnny");
    }
};

Person.getName();


});

You do not need to re-assign Person to a new variable, you can just access it directly here. You also put Person in quotes, which means that your myContext variables referenced a string with the word "Person".

Now, what I think you actually want to do is build a constructor function, from your use of new.

http://jsfiddle.net/2v0xnoyf/

Here's how that'd actually be done:

$(document).ready(function () {

    //You need to make it a function that returns an object
    var Person = function (name) {

        return {

            getName: function () {
                alert(name);
            }

        }

    };

    //Then we create an instance of Person and pass in the name as an argument
   var johnny = new Person('Johnny');
    johnny.getName();


});

You'll see that instead of making Person an object, we made it a function that returns an object, and we used a function argument to act as a placeholder for the name. This way we can create as many people as we want, and we don't have to redefine Person every single time. For example, if we wanted to make some more people, we'd just do:

var sam = new Person('Sam');
var jim = new Person('Jim');

Now sam.getName() will alert 'Sam' and jim.getName() will alert 'Jim'.

2 Comments

Thank you Kierkegaurd, I edited my question to say what I'm really trying to achieve. I tried to simplify it too much at first (to save everyone some time), but I made my intentions very unclear.
Felix's updated advice is solid, you should almost always avoid dynamically evaluating Javascript from strings like that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.