SrdjaNo1
SrdjaNo1

Reputation: 899

Methods in JS class - why the code throws error?

Does anyone know why in the code example below JS throws an error when ES6 classes are just syntactical sugar on top of the constructor function and prototype pattern?

// Example 1
class Cat {
  meow() {
    console.log('Meow meow!')
  }
}

let kitty = {};
Object.assign(kitty, Cat.prototype);
kitty.meow(); // TypeError: kitty.meow is not a function

Why then this code snippet works when it should be functionally the same as the one from above?

class Cat {

}

Cat.prototype.meow = function() {console.log('Meow meow!')}

let kitty = {};
Object.assign(kitty, Cat.prototype);
kitty.meow(); // Meow meow!

Upvotes: 0

Views: 79

Answers (1)

Angel Politis
Angel Politis

Reputation: 11313

Object.assign copies the enumerable properties of one or more source objects to a target object. Unless defined so, methods are by default non-enumerable. Object.create on the other hand, can create a new instance of your class if, for some reason, you want to do it this way.

class Cat {
  meow() { console.log('Meow meow!') }
}

let kitty = Object.create(Cat.prototype);
kitty.meow();

An example to illustrate how Object.assign works would be the following. In the example below, using Object.assign copies the enumerable properties of the two Cat instances to kitten3, which has a mix of their properties but is NOT itself a Cat instance.

var id = 1;

class Cat {
  constructor(name) {
    this.id = id++;
    if (name) this.name = name;
  }
}

let kitty1 = new Cat("Lucy");
console.log(kitty1.id, kitty1.name, kitty1 instanceof Cat);

let kitty2 = new Cat();
console.log(kitty2.id, kitty2.name, kitty2 instanceof Cat);

let kitty3 = {};
Object.assign(kitty3, kitty1, kitty2);
console.log(kitty3.id, kitty3.name, kitty3 instanceof Cat);

In your updated code where you set Cat.prototype.meow = function() {}, you do so directly which makes it an enumerable property of the object (prototype), which is why Object.assign works. You can see the difference using Object.keys. A closer equivalent to the first declaration would be to define the method using Object.defineProperty and making it non-enumerable:

class Cat1 {
  meow() { console.log('Meow meow!') }
}

class Cat2 {}
Cat2.prototype.meow = function() { console.log('Meow meow!') }

class Cat3 {}
Object.defineProperty(Cat3.prototype, "meow", {
  value: function() { console.log('Meow meow!') },
  enumerable: false
});

console.log("Cat1: ", Object.keys(Cat1.prototype));
console.log("Cat2: ", Object.keys(Cat2.prototype));
console.log("Cat3: ", Object.keys(Cat3.prototype));

Upvotes: 6

Related Questions