2

I have the following code:

class Pet {
    constructor(name) {
        this.petName = name;
    }
}

Pet.prototype.speak = {
    name: function() {
        console.log(this.petName);
    }
};

// -----------------------------------------------

const myPet = new Pet("Max");
myPet.speak.name();

I expect this code to print Max, but instead it prints undefined.

If I change the console.log to console.log(this); it prints { name: [Function: name] }. Which makes me think that function doesn't have access to the instance properties.

How can I ensure that this function has access to the instance?

1
  • 1. name refers to the function, it should be petName. 2. this doesn't refer to the object anymore but instead to the object the function is called in (in this case the object containing only the name() method) Commented Dec 9, 2018 at 19:20

2 Answers 2

3

If you're targetting or have support for ES6 language features, one way to achieve what you want would be via a get method combined with an arrow function.

The get method would be declared get speak() which means it can be called without paranthesis. This method would return an object that contains a name() arrow function. Use of the arrow function here allows you to access the enclosing Pet instance via the this keyword directly:

class Pet {
    constructor(name) {
        this.petName = name;
    }
    
    // Get method allows the speak method to be called without ()
    get speak() {
      return {
        // Arrow function causes this.petName to refer to petName 
        // field of this class instance 
        name: () => {
          console.log(this.petName);
        }
      }
    }
}
 
const myPet = new Pet("Max");
myPet.speak.name();

const yourPet = new Pet("Min");
yourPet.speak.name();

Here is more information on the get method syntax and language feature.

Sign up to request clarification or add additional context in comments.

5 Comments

I think this might work. Going to try it soon. Not quite the way I was thinking of it working. But it should work I think.
@CharlieFish sure, let me know if you have any questions or need anything clarified on this
Awesome. I think this will work. One last question tho. How does this differ from using a prototype? I know prototypes tend to be better in terms of memory usage and performance a bit. Does this behave similarly to that, or does it have the same problems as the non-prototype based solutions?
@CharlieFish great to hear this has helped - please consider accepting the answer if it meets your requirements. Sorry I can't give your answer justice in this small comment area however you will find this article useful for clarification medium.com/javascript-scene/…
@Charlie class is basically just syntactic sugar for prototypes. With this answer, the speak getter is defined on Pet.prototype, but speak.name is recreated each time that getter is called.
1

When you call a function like this: myPet.speak.name(); then inside that function this refers to myPet.speak. In your case that is an object with one property (name) whose value is a function.

If you make speak itself be a function instead of an object, and use the property petName instead of name, it will work:

class Pet {
    constructor(name) {
        this.petName = name;
    }
}

Pet.prototype.speak = function() {
    // myPet has a `petName` property, but no `name` property
    console.log(this.petName);
};

const myPet = new Pet("Max");
myPet.speak(); // this will be `myPet` inside the function

3 Comments

The goal is to have myPet.speak be an object, and name to be a method of that, that logs the name. This is to make the API as easy as possible.
@CharlieFish That's not easy. Better just call the method speakName.
@Pual but if I use arrow function like this Pet.prototype.speak = () => this.petName this will not work

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.