1

I am having an issues extending an object with another object in ECMA6. After I have extended the object in question it says it cannot find the method on the updated object. Here is my code:

Subject class:

// Subject to be observed
class Subject {
    constructor() {
        this.observers = new ObserverList();
    }

    addObserver(observer) {
        this.observers.add(observer);
    }

    removeObserver(observer) {
        this.observers.removeAt(this.observers.indexOf( observer, 0 ));
    }

    notify(context) {
        for(let i = 0; i < this.observers.count(); i++) {
            this.observers.get(i).update(context);
        }
    }
}

And my code where the object is extended:

/**
 * Function to extend an object with another object
 */
function extend(obj, extension) {
    Object.assign(obj, extension);
}

// Get our DOM elements
let controlCheckbox = document.getElementById("mainCheckbox"),
    addBtn = document.getElementById("addNewObserver"),
    container = document.getElementById("observersContainer");


// Concrete subject
// extend controlling checkbox with Subject class
extend(controlCheckbox, new Subject());

// Clicking the checkbox will trigger notifications to it's observers
controlCheckbox.onclick = () => {
    controlCheckbox.notify(controlCheckbox.checked);
};

addBtn.onclick = addNewObserver;

function addNewObserver() {
    let check = document.createElement('input');
    check.type = 'checkbox';

    extend(check, new Observer());
    check.update = function(value) {
        this.checked = value;
    };
    controlCheckbox.addObserver(check);
    container.appendChild(check);
}

When the onclick is fired it is saying that the method controlCheckbox.addObserver is not defined. I have added a breakpoint to view the controlCheckbox object and I can see that method is available in the prototype. Should this not work? Can anyone point out where I am going wrong?

5
  • "The Object.assign() method only copies enumerable and own properties from a source object to a target object." developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Commented Jan 18, 2017 at 14:05
  • 2
    Given ES2015, I don't understand why you're not using the proper extends keyword to create the subclass. Commented Jan 18, 2017 at 14:08
  • 1
    It's not a sub-class? It's a DOM element object that needs to inherit the Subject class Commented Jan 18, 2017 at 14:10
  • ah, you're trying to mixin your class into a DOM class? Commented Jan 18, 2017 at 14:11
  • Indeed. I know there are other solutions I was just wondering if this was possible. :) Commented Jan 18, 2017 at 14:14

2 Answers 2

1

Object.assign only copies own enumerable properties from the source objects to the target. Your Subject object only has one own property: observers. All of the others (the methods) are inherited, not "own".

You'll need to write your own version of extend that handles inherited properties as well if you want to have them copied to the target.

The other issue is that by default, your methods won't be enumerable, either, so just a simple for-in won't find them. You'd need to use getOwnPropertyNames and getPrototypeOf.

For instance:

function extend(target, ...sources) {
    for (const source of sources) {
        for (let obj = source; obj && obj !== Object.prototype; obj = Object.getPrototypeOf(obj)) {
            for (const name of Object.getOwnPropertyNames(obj)) {
                if (!(name in target)) {
                    target[name] = obj[name];
                }
            }
        }
    }
    return target;
}

...but that's very quick and dirty, just concept. Note how I stopped at Object.prototype rather than copying toString and such.


Side note: Extending DOM elements in the way you are leaves you fairly open to conflicts with methods added to the DOM in the future, or by other libraries, etc. You may be fine with that, but it would worry me. Wrapping elements (like jQuery does) would be my preference.

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

Comments

0

No, Object.assign doesn't copy anything from proto.

console.log(Object.assign({}, Object.create({x:9})).x)

Just wrap dom-element by the Subject and work with you class.

1 Comment

@T.J.Crowder, ooops. Removed that part.

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.