The Web Developer Bootcamp 2024

Colt Steele

Back to OOP Index Page


oop - Classes

We have been building up our Color Converter app in the previous discussions, and so far, we have discussed Prototypes, Factory Functions, and Constructor Functions. We have seen how these processes work and while using a Constructor Function greatly improved our code efficiency over our Factory Function, we can improve our code even more by using Classes.

As a refresher, here is the Constructor Function code:

  • JavaScript
  •  
  • // create the Constructor Function
  • // adds default values for r/g/b
  • function MakeColor ( r = 190, g = 155, b = 90 ) {
    • this.r = r;
    • this.g = g;
    • this.b = b;
  • };
  •  
  • // create the rgb [[prototype]] method
  • MakeColor.prototype.rgb = function() {
    • const { r, g, b } = this;
    • return `rgb(${r}, ${g}, ${b})`;
  • };
  •  
  • // create the rgba [[prototype]] method
  • // adds default value for the alpha channel
  • MakeColor.prototype.rgba = function( a = 1.0 ) {
    • const { r, g, b } = this;
    • return `rgba(${r}, ${g}, ${b}, ${a})`;
  • };
  •  
  • // create the hex [[prototype]] method
  • MakeColor.prototype.hex = function() {
    • const { r, g, b } = this;
    • return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)
  • };
  •  
  • // Call the color object
  • // because we set default color values in the Constructor
  • // any, or all of the input values are optional
  • const newColor = new MakeColor();
  •  
  • // Use the newColor object
  • console.log(`newColor.rgb = ${newColor.rgb()}`);
    • // outputs newColor.rgb = rgb(190, 155, 90)
  • console.log(`newColor.rgba = ${newColor.rgba(0.5)}`); // overrides the default opacity of 1.0
    • // outputs newColor.rgba = rgba(190, 155, 90, 0.5)
  • console.log(`newColor.hex = ${newColor.hex()}`);
    • // outputs newColor.hex = #be9b5a

While this is a much better approach over our Factory Function, We can improve the coding even more by creating a Class.

Creating a Class

One of the biggest advantages of using a Class structure over a Constructor Function is that any methods that we create will be contained within the Class structure itself, and not externally to the Class function.

Let's start be defining our new Class. You start by designating the keyword class followed by the Capitalized Name of the class:

  • class MakeColor {
  • }

The next step is to add a Constructor Function to our class. This must be the first designation after creating our new class and is required. Also note, the keyword name of constructor can not be changed.

  • class MakeColor {
    • constructor() {
    • }
  • }

The constructor will run immediately when this class is called and it works exactly like our previous "constructor function" we created in the Constructor Functions discussion. We pass in our variables and assign them to this, like so:

  • class MakeColor {
    • constructor ( r = 215, g = 170, b = 80, name = 'Bronze' ) {
      • this.r = r;
      • this.g = g;
      • this.b = b;
      • this.name = name;
    • }
  • }

You may notice something new here. We've added an additional variable called name, to our constructor. This is optional but gives us the ability to "name" the color we are defining, such as "Red", "Coral", "Bronze", or whatever you like.

So now all of our class Variables have been defined within our class constructor, and if you call this class like so:

  • const color1 = new MakeColor();
  • console.log(color1);
and look at the console log you will see that we have indeed created an object, and that inside of the [[prototype]] for our object, we have our constructor.

Adding the Methods

So we now have our basic class built, along with it's Constructor Function and all is working properly.

So let's start adding our methods to our class. Here is where using a Class is better than using a Constructor Function:

  1. Our methods are contained within the Class structure itself, so everything is more organized.
  2. When defining our method, we do not use the [[prototype]] designation (constructorFunctionName.prototype.methodName)

Add a method:

  • rgb() {
    • const { r, g, b, name } = this;
    • return `${name} = rgb(${this.innerRGB()})`;
  • }
and as you see, all we have to do is provide the method name and functionality. No need for the [[prototype]] designation, and this method is included within the class structure.

So, once we add all of our methods, we end up with the same functionality as we had with our Constructor Functions, but the code is cleaner and easier to read. It's a big plus to have the constructor and All of the methods contained within the one Class Structure.

Final Code
  • JavaScript
  • // Create the Class
  • class RgbConvert {
    • // sets default values
    • constructor ( r = 215, g = 170, b = 80, colorName = 'Bronze' ) {
      • this.r = r;
      • this.g = g;
      • this.b = b;
      • this.colorName = .colorName;
      • this.calcHSL(); // run method to convert rgb to hsl
    • }
    •  
    • // Create the Methods
    • // method to output color name
    • name() {
      • const colorName = this.colorName;
      • return `Color Name is: ${colorName}`;
    • }
    • // create a "base" method to use in the rgb methods
    • innerRGB() {
      • const { r, g, b } = this;
      • return `$r}, ${g}, ${b}`;
    • }
    • // Output the RGB Color String
    • rgb() {
      • return `rgb(${this.innerRGB()})`;
    • }
    • // Output the RGBA Color String
    • rgba(a = 1.0) {
      • return `rgba(${this.innerRGB()}, ${a})`;
    • }
    • // convert rgb to hex method
    • hex() {
      • const { r, g, b } = this;
      • return '#' + ((1 << 24) + (r << 16) + (g << 8) + (b).toString(16).slice(1));
    • }
    • // =================================
    • // added hsl methods
    • // method to output hsl color
    • hsl() {
      • const { h, s, l } = this;
      • return `hsl(${h}, ${s}%, ${l}%)`;
    • }
    • // method to output opposite hsl color
    • opposite() {
      • const { h, s, l } = this;
      • const newHue = (h + 180) % 360;
      • return `hsl(${newHue}, 100%, ${l}%)`;
    • }
    • // convert rgb to hsl
    • calcHSL() {
      • let { r, g, b } = this;
      • // Make r, g, and b fractions of 1
      • r /= 255;
      • g /= 255;
      • b /= 255;
      • // Find greatest and smallest channel values
      • let cmin = Math.min(r, g, b),
        • cmax = Math.max(r, g, b),
        • delta = cmax - cmin,
        • h = 0,
        • s = 0,
        • l = 0;
      • if (delta == 0) h = 0;
      • else if (cmax == r)
        • // Red is max
        • h = ((g - b) / delta) % 6;
      • else if (cmax == g)
        • // Green is max
        • h = (b - r) / delta + 2;
      • else
        • // Blue is max
        • h = (r - g) / delta + 4;
      • h = Math.round(h * 60);
      • // Make negative hues positive behind 360°
      • if (h < 0) h += 360;
      • // Calculate lightness
      • l = (cmax + cmin) / 2;
      • // Calculate saturation
      • s = delta == 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
      • // Multiply l and s by 100
      • s = +(s * 100).toFixed(1);
      • l = +(l * 100).toFixed(1);
      • this.h = h;
      • this.s = s;
      • this.l = l;
    • }
  • }
  •  
  • // Call the RgbConvert Class
  • const bronze = new RgbConvert();
  • const teal = new RgbConvert(0, 195, 195, 'Teal');
  •  
  •  
  • // function to convert hex to rgb
  • function hexToRgb ( hex = 'a82aaa' ) {
    • let r = parseInt(hex.substring(0,2), 16);
    • let g = parseInt(hex.substring(2,4), 16);
    • let b = parseInt(hex.substring(4), 16);
    • return `HEX Color #${hex} = rgb(${r}, ${g}, ${b})`;
  • }
  •  
  • // run the hex to rgb function
  • const hexColor = hexToRgb(); // input hex number as string, no # sign

Notice that when we call bronze, we did not designate any color values. This is to demonstrate how the class will set the default values set within the class structure.

Also notice that we inserted a "base" method to use in the rgb methods. This was done simply to demonstrate how to utilize a method from within another method.

We also added a method to convert RGB to HSL, and also a method to return the opposite HSL value, for determining the opposite color on the color wheel.

And finally, we added a function to convert a hex number into an rgb number.


Back to Top