Reputation: 2860
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?
Upvotes: 1
Views: 94
Reputation: 21400
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.
Upvotes: 0
Reputation: 1074465
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.
Upvotes: 1