Search code examples
javascriptclassinheritanceprototype

How can some methods be in the prototype but not be passed around via Object.assign, while some others are


Take the following classes A, B and C and their instances a, b and c

class A {
    constructor() {
        this.method1 = function() {}
    }

    method2() {}
}

A.prototype.method3 = function() {};


class B extends A {
    constructor() {
        super();
    }
}


class C {
    constructor() {}
}

Object.assign(C.prototype, A.prototype);

const a = new A();
const b = new B();
const c = new C();

How come class B inherits method 2 but class C doesn't?

How can the following statements be both true ?

A.prototype.method2 !== undefined
c.method2 === undefined

In case you are wondering, c.method3 !== undefined, so there is some fundamental difference between the two that I cannot grasp.

You can fiddle around with it here https://jsfiddle.net/pdn64bv2/


Update

I thought it would be useful to share how to achieve the effect I was expecting Object.assign(C.prototype, A.prototype) to produce.

Object.getOwnPropertyNames(A.prototype).forEach(name => {
  if (name !== "constructor") C.prototype[name] = A.prototype[name];
});

This copies the prototype of A to C, including non-enumerable properties.

Note that it does not copy the hole prototype chain the way Reflect.setPrototypeOf(C.prototype, A.prototype) would, which may be interesting for object composition.


Solution

  • There are two things conspiring to have this effect:

    1) Object.assign will only copy the enumerable own properties of an object. Any non-enumerable properties will not be copied

    2) When you use the class keyword, any methods you define are not enumerable. This is different from when you assign something to an object with A.prototype.method3 = function() {}, where the property will be enumerable.

    So since A.prototype.method2 is not enumerable, it does not get put onto C.prototype when you do Object.assign(C.prototype, A.prototype);

    Another way to see that class methods aren't enumerable is to use Object.keys. The ones defined with the class keyword are not there:

    class A {
        constructor() {
            this.method1 = function() {}
        }
    
        method2() {}
    }
    
    A.prototype.method3 = function() {};
    
    console.log(Object.keys(A.prototype));
    
    console.log(A.prototype.method2); // it's there
    console.log(Object.prototype.propertyIsEnumerable('method2')); // but it's not enumerable