Emmitt Gregory
Emmitt Gregory

Reputation: 3

JavaScript prototype problem

If I call myRobot.Speak.sayHi() it always returns undefined. Please, what am I doing wrong? Thanks for reply!

var Factory = (function() {

    // Constructor  
    var Robot = function() {

    };

    // Public
    return {
        extendRobot: function(power, methods) {
            Robot.prototype[power] = methods;
        },
        createRobot: function() {
            return new Robot();
        }
    };

}());

Factory.extendRobot('Speak', {
    sayHi: function() {
        return 'Hi, ' + this.name;
    }
});

var myRobot = Factory.createRobot();
myRobot.name = 'Robin';
myRobot.Speak.sayHi() // => ‘Hi, Robin’

Upvotes: 0

Views: 250

Answers (3)

Raynos
Raynos

Reputation: 169511

createRobot: function() {
    var r = new Robot();
    for (var k in r.Speak) {
        if (typeof r.Speak[k] === "function") {
            r.Speak[k] = r.speak[k].bind(r);
        }
    }
    return r;
}

Rather then returning a new robot, make sure to bind all the methods in your powers to the robot.

To avoid hard coding in the loops try this:

Robot.powers = [];
...
extendRobot: function(power, methods) {
    Robot.powers.push(power);
    Robot.prototype[power] = methods;
},
createRobot: function() {
    var robot = new Robot();
    Robot.powers.forEach(function(power) {
        for (var method in robot[power]) {
            if (typeof robot[power][method] === "function") {
                robot[power][method] = robot[power][method].bind(robot);
            }
        }
    });
    return robot;
}

This relies on Function.prototype.bind so use the ES5 shim or use underscore for supporting old browsers (IE<9)

Upvotes: 2

AsherMaximum
AsherMaximum

Reputation: 972

insert name : this.name before the line sayHi: function() { and then it should work

Upvotes: 0

brymck
brymck

Reputation: 7663

myRobot.Speak.name = 'Robin';

In your case, this refers to Robot.Speak, not the parent object Robot.

Upvotes: 2

Related Questions