Reputation: 11313
I'm making an object that receives a selector as an argument, which has one method named stylise
, which is used to make alterations to the CSS of the HTML element(s) selected.
Code:
/* ----- JavaScript ----- */
function get(selector) {
var
self = {},
elements = Array.from(document.querySelectorAll(selector));
this.stylise = function(object) {
Object.keys(object).forEach(function(propertyName) {
for (var index = 0; index < elements.length; index++) {
elements[index].style[propertyName] = object[propertyName];
};
});
};
return Object.setPrototypeOf(self, this.prototype);
};
<!----- HTML ----->
<input id = "text" type = "text" style = "padding: .5em .7em;"/>
If the line return Object.setPrototypeOf(self, this.prototype);
is skipped the above code will work as expected by calling it like:
var a = new get("#text");
a.stylise({
backgroundColor: "yellow",
borderRadius: "5px"
});
However, I want the above to work by calling it like:
get("#text").stylise({
backgroundColor: "yellow",
borderRadius: "5px"
});
I tried to achieve that by using Object.setPrototypeOf(self, this.prototype)
, but to no avail as I got the following error in the console: Object doesn't support property or method 'stylise'
.
What part of my code is causing this and how can I resolve this?
Upvotes: 1
Views: 66
Reputation: 1074018
You don't need setPrototypeOf
for that (there are very, very few situations where it's what you would reach for), just have get
return the object you've created and assigned to self
and assign to self.stylise
rather than this.stylise
:
/* ----- JavaScript ----- */
function get(selector) {
var
self = {},
elements = Array.from(document.querySelectorAll(selector));
self.stylise = function(object) {
Object.keys(object).forEach(function(propertyName) {
for (var index = 0; index < elements.length; index++) {
elements[index].style[propertyName] = object[propertyName];
};
});
};
return self;
}
get("#text").stylise({
backgroundColor: "yellow",
borderRadius: "5px"
});
<!----- HTML ----->
<input id = "text" type = "text" style = "padding: .5em .7em;"/>
In fact, you can create stylise
within the object initializer. You can also use forEach
on elements
:
/* ----- JavaScript ----- */
function get(selector) {
var elements = Array.from(document.querySelectorAll(selector));
return {
stylise: function(object) {
Object.keys(object).forEach(function(propertyName) {
elements.forEach(function(element) {
element.style[propertyName] = object[propertyName];
});
});
}
};
}
get("#text").stylise({
backgroundColor: "yellow",
borderRadius: "5px"
});
<!----- HTML ----->
<input id="text" type="text" style="padding: .5em .7em;" />
You've said elsewhere that you want to define stylise
outside the constructor (and that putting elements
on the object was fine). If so, you do that by using Object.create
to create an object backed by a specific prototype object (in our case, get.prototype
); this does what new
does when it creates objects before calling the constructor, but you've said you don't want to use new
.
Note that this example first creates two objects via get
, then calls stylise
on them; the various attempts you posted trying to do this would fail in that scenario:
/* ----- JavaScript ----- */
// The builder function
function get(selector) {
// Create a new object we'll return, backed by `get.prototype`
var obj = Object.create(get.prototype);
// Put the elements matching the selector on it
obj.elements = Array.from(document.querySelectorAll(selector));
// Return it
return obj;
}
// Add `stylise` to the prototype `get` assigns objects
get.prototype.stylise = function(object) {
// Get our elements, so we don't have to worry about `this` in the callbacks below
var elements = this.elements;
// Style them
Object.keys(object).forEach(function(propertyName) {
elements.forEach(function(element) {
element.style[propertyName] = object[propertyName];
});
});
};
// Using it
var t1 = get("#text1");
var t2 = get("#text2");
t1.stylise({
backgroundColor: "yellow",
borderRadius: "5px"
});
t2.stylise({
backgroundColor: "green",
borderRadius: "10px"
});
<!----- HTML ----->
<input id="text1" type="text" style="padding: .5em .7em;" />
<input id="text2" type="text" style="padding: .5em .7em;" />
Side note: Function declarations don't need ;
after them (although putting one there is harmless). ;
is for terminating statements. Declarations aren't statements.
Upvotes: 5