I'm currently building a game engine (this is more related to a 2d renderer) and I would like to know if it's bad practice to, for example, have an object Image that only keeps the url, width and height of the image. Then when you render this Image the renderer will request to load the image, and also the renderer knows how to render the image.
Why I've chosen such an approach?
Also a rectangle will have a x, y, width and height but it doesn't know how to draw itself, the renderer draws the rectangle.
What might be bad in this approach?
Obviously, it depends.
You're asking a harder question than just "should my nodes render themselves."
if you want the real OOP answer to the more general question "how should I design my objects/classes?", check out Uncle Bob's SOLID Design principles. Or just do a search for "SOLID Design".
In this specific scenario, I'd say having objects which represent that data only and other objects which are capable of drawing those objects is a perfectly valid idea. In this way, you use the same "data objects" for multiple different types of views of that data, such as you're currently explaining.
Your idea is border-line MVC or MVVM (in principal), so it is not without merit.
I would like to know if is a bad practice for example to have an object Image that only keeps the url, width and height of the image.
Simply put, no. This is not bad practice in and of itself. The fact that it is called "Image" is bad because that's an existing "class" for creating an <img>
tag. It will probably best to pick a different name for that.
Then when you render this Image the renderer will request to load the image and also the renderer knows how to render the image.
This smells complex. This object will need to handle the callback for when the image is loaded, or find some way of synchronously loading the image (which is bad, if even possible). It will also need to know what to do when an image fails to load. I might consider using a promise on the previously mentioned "data object" to help with part of this complexity, because any class which uses the data object will most likely need to load the image.
Another observation: You use the term "Renderer" like it's some all-encompasing thing that can render anything and everything because it's sole responsibility is to be able to do that one thing. If that's what you're thinking, then that's not going to work out so well in the long run. There will need to be specific objects which know how to render other data-only objects in a certain way. Those "view" objects will know how to draw those data-only objects using some kind of "rendering" api, but the drawing api should be thought of as a utility, or as something which hides the complexity of drawing primitive objects. Don't think of it as your "go to guy" that knows how to "draw anything/everything".
Also a rectangle will have a x, y, width and height but it doesn't know how to draw itself, the renderer draw the rectangle.
Sounds good. By doing this, you allow the rectangle to be drawn in any which way you need it to be drawn. For instance, red, blue, radial gradient, transformed according to some matrix, etc.
What might be bad in this approach?
Anything... Everything... Nothing... but most likely, un-needed complexity. Assuming that the complexity is in fact, un-needed.
Sometimes we just need to code something to find out.
Just don't waste time thinking about "what are all of the ways I will need to use this in the future" or "how do I make this the most generic solution possible", because you'll end up spending a lot of time getting nothing done.