Tag: programming

HTML is Not a Programming Language?

HTML is not a programming language.

I’ve heard that sentence so many times and it’s tiring. Normally, it is followed by something like, It doesn’t have logic, or, It is not Turing complete,.so… obviously it is not a programming language. Like it’s case-closed and should be the end of the conversation.

Should it be, though?

I want to look at typical arguments I hear used to belittle HTML and offer my own rebuttals to show how those claims are not completely correct.

My goal is not to prove that HTML is or is not a programming language, but to show that the three main arguments used for claiming it is not are flawed or incorrect, thus invalidating the conclusion from a logical point of view.

“HTML is a markup language, not a programming language”

This statement, by itself, sounds great… but it is wrong: markup languages can be programming languages. Not all of them are (most are not) but they can be. If we drew a Venn diagram of programming languages and markup languages, it would not be two separate circles, but two circles that slightly intersect:

A markup language that operates with variables, has control structures, loops, etc., would also be a programming language. They are not mutually exclusive concepts.

TeX and LaTeX are examples of markup languages that are also considered programming languages. It may not be practical to develop with them, but it is possible. And we can find examples online, like a BASIC interpreter or a Mars Rover controller (which won the Judges’ prize in the ICFP 2008 programming contest).

While some markup languages might be considered programming languages, I’m not saying that HTML is one of them. The point is that the original statement is wrong: markup languages can be programming languages. Therefore, saying that HTML is not a programming language because it is a markup language is based on a false statement, and whatever conclusion you arrive at from that premise will be categorically wrong.

“HTML doesn’t have logic”

This claim demands that we clarify what “logic” means because the definition might just surprise you.

As with Turing-completeness (which we’ll definitely get to), those who bring this argument to the table seem to misunderstand what it is exactly. I’ve asked people to tell me what they mean by “logic” and have gotten interesting answers back like:

Logic is a sensible reason or way of thinking.

That’s nice if what we’re looking for is a dictionary definition of logic. But we are talking about programming logic, not just logic as a general term. I’ve also received answers like:

Programming languages have variables, conditions, loops, etc. HTML is not a programming language because you can’t use variables or conditions. It has no logic.

This is fine (and definitely better than getting into true/false/AND/OR/etc.), but also incorrect. HTML does have variables — in the form of attributes — and there are control structures that can be used along with those variables/attributes to determine what is displayed.

But how do you control those variables? You need JavaScript!

Wrong again. There are some HTML elements that have internal control logic and don’t require JavaScript or CSS to work. And I’m not talking about things like <link> or <noscript> – which are rudimentary control structures and have been part of the standard for decades. I’m referring to elements that will respond to the user input and perform conditional actions depending on the current state of the element and the value of a variable. Take the <details>/<summary> tuple or the <dialog> element as examples: when a user clicks on them, they will close if the open attribute is present, and they will open if it is not. No JavaScript required.

So just saying alone that HTML isn’t a programming language because it lacks logic is misleading. We know that HTML is indeed capable of making decisions based on user input. HTML has logic, but it is inherently different from the logic of other languages that are designed to manipulate data. We’re going to need a stronger argument than that to prove that HTML isn’t a form of programming.

“HTML is not ‘Turing complete’”

OK, this is the one we see most often in this debate. It’s technically correct (the best kind of correct) to say HTML is not Turing complete, but it should spark a bigger debate than just using it as a case-closing statement.

I’m not going to get into the weeds on what it means to be Turing complete because there are plenty of resources on the topic. In fact, Lara Schenck summarizes it nicely in a post where she argues that CSS is Turning complete:

In the simplest terms, for a language or machine to be Turing complete, it means that it is capable of doing what a Turing machine could do: perform any calculation, a.k.a. universal computation. After all, programming was invented to do math although we do a lot more with it now, of course!

Because most modern programming languages are Turing complete, people use that as the definition of a programming language. But Turing-completeness is not that. It is a criterion to identify if a system (or its ruleset) can simulate a Turing machine. It can be used to classify programming languages; it doesn’t define them. It doesn’t even apply exclusively to programming languages. Take, for example, the game Minecraft (which meets that criterion) or the card game Magic: The Gathering (which also meets the criterion). Both are Turing complete but I doubt anyone would classify them as programming languages.

Turing-completeness is fashionable right now the same way that some in the past considered the difference between compiled vs. interpreted languages to be good criteria. Yes. We don’t have to make a big memory effort to remember when developers (mainly back-end) downplayed front-end programming (including JavaScript and PHP) as not “real programming.” You still hear it sometimes, although now faded, mumbled, and muttered.

The definition of what programming is (or is not) changes with time. I bet someone sorting through punched cards complained about how typing code in assembly was not real programming. There’s nothing universal or written in stone. There’s no actual definition.

Turing-completeness is a fair standard, I must say, but one that is biased and subjective — not in its form but in the way it is picked. Why is it that a language capable of generating a Turing Complete Machine gets riveted as a “programming language” while another capable of generating a Finite State Machine is not? It is subjective. It is an excuse like any other to differentiate between “real developers” (the ones making the claim) and those inferior to them.

To add insult to injury, it is obvious that many of the people parroting the “HTML is not Turing complete” mantra don’t even know or understand what Turing-completeness means. It is not an award or a seal of quality. It is not a badge of honor. It is just a way to categorize programming languages — to group them, not define them. A programming language could be Turing complete or not in the same way that it could be interpreted or compiled, imperative or declarative, procedural or object-oriented.


So, is HTML a programming language?

If we can debase the main arguments claiming that HTML is not a programming language, does that actually mean that HTML is a programming language? No, it doesn’t. And so, the debate will live on until the HTML standard evolves or the “current definition” of programming language changes.

But as developers, we must be wary of this question as, in many cases, it is not used to spark a serious debate but to stir controversy while hiding ulterior motives: from getting easy Internet reactions, to dangerously diminishing the contribution of a group of people to the development ecosystem.

Or, as Ashley Kolodziej beautifully sums it up in her ode to HTML:

They say you’re not a real programming language like the others, that you’re just markup, and technically speaking, I suppose that’s right. Technically speaking, JavaScript and PHP are scripting languages. I remember when it wasn’t cool to know JavaScript, when it wasn’t a “real” language too. Sometimes, I feel like these distinctions are meaningless, like we built a vocabulary to hold you (and by extension, ourselves as developers) back. You, as a markup language, have your own unique value and strengths. Knowing how to work with you best is a true expertise, one that is too often overlooked.

Independent of the stance that we take on the “HTML is/isn’t a programming language” discussion, let’s celebrate it and not deny its importance: HTML is the backbone of the Internet. It’s a beautiful language with vast documentation and extensive syntax, yet so simple that it can be learned in an afternoon, and so complex that it takes years to master. Programming language or not, what really matters is that we have HTML in the first place.


The post HTML is Not a Programming Language? appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, ,

So you want to self-publish books and courses on programming

John Resig and I recently self-published our book on GraphQL. There are tons of how-tos for self-publishing a book, or even online classes, but very little in the way of why you would want to, or whether it’s even worth your while. I’m going to share my experience and revenue numbers with you in this post, as well as those from others who have self-published material. I’ll go specifically into the pros and cons of self-publishing books and courses in tech.

Revenue

This is probably what you’re most curious about, right? When I originally started working on our book, I sent a book proposal to publishers. But by the time John and I joined forces, we were both set on self-publishing. He had written two popular JavaScript books and a blog post about traditional publishing for programming books, which includes:

  • Programmers aren’t that into reading books! Programming books, by and large, are poor sellers. They rarely sell more than 4,000 copies.
  • He made $ 7,500 on his first 4,000 copies, where his royalty rate started at 10% for print sales and 20% for digital copies.

On the topic of traditional publishing revenue, Randall Kanna says: “Nothing comes from a tech book. Just the credibility.” A book can make significantly more, but it’s rare. Martin Kleppmann’s book on machine learning was O’Reilly’s second most popular seller in 2019, and he made $ 478,000 in the first three years (with 108,000 copies sold, a 10% royalty on print sales, and a 25% royalty on digital sales).

The Pragmatic Bookshelf is the outlying publisher when it comes to royalties: it gives authors 50% of gross profit. In their first 10 years operating, 42% of their authors made more than $ 50,000, and 12% made more than $ 100,000.

That said, self-publishing has much higher royalty rates:

  • Amazon: 70% (for e-books; 60% minus printing cost for printed books)
  • Leanpub: 80%
  • Gumroad: 96.5% ($ 10 monthly membership fee)
  • Your own website: 97%

This gives authors the potential to make more money. Discover Meteor was probably the most successful self-published programming book of its time, with around $ 500,000 in sales (9,000 copies) between 2013 (when they launched) and 2018 (when they made it available for free). The authors Sacha Grief and Tom Coleman put a lot of effort into marketing it (described in their Gumroad case study), and it became the recommended learning resource in the Meteor community. The current best-selling book is Adam Wathan and Steve Schoger’s Refactoring UI, which I believe passed $ 2 million in 2020! 🤑 Their success was also largely due to their ability to market the book, in addition to addressing a significant need for a broad audience (practical user interface design for front-end developers).

That’s books. Looking at publishing video courses, there are a few options:

Like self-published books, self-published courses have a lot of potential. Level Up Tutorials, Kent C. Dodds, and Wes Bos don’t share revenue numbers for their courses, but I’m assuming they have made considerable sums. Wes, for example, has sold his courses to over 140,000 people at the time of writing!

Those are the outliers, of course. The majority of resources out there make significantly less. Take, for example, the self-published books in the GraphQL space that we were entering:

Title (Author) Sales Price Estimated Revenue
Production Ready GraphQL (Marc-André Giroux) 3,000 (this is a guess) $ 49–$ 79 $ 147,000–$ 237,000
The Road to GraphQL (Robin Wieruch) 2,250 $ 30–$ 80 $ 67,500–$ 180,000
The GraphQL Guide (John Resig and Loren Sands-Ramshaw) 1,000 $ 30–$ 279 $ 78,000 in sales; $ 68,000 in sponsorships
Advanced GraphQL with Apollo & React (Mandi Wise) 200 $ 30–$ 45 $ 10,000+
Fullstack GraphQL (Julian Mayorga) 100 $ 39 $ 3,000

So, yes, the potential is big. But it’s not a guarantee.

Self-publishing pros and cons

Pros Cons
Potential for more revenue. You get to set the price, sell different packages, and receive a larger cut. It’s much harder. A publisher does a ton of things for you: editing, gathering feedback from technical reviewers, the build toolchain, translating, an online store, getting it on Amazon and other bookstores, customer service, tracking errata, etc. Doing all of these things yourself takes a lot of time, especially if you also decide to build a Gatsby site to display the text online. 😜
Flexibility. You get to decide what goes into the book as well as how it’s formatted and sold. No built-in marketing or distribution. The success of your own book completely depends on your ability to market it. This is hard, as you can read in swyx’s notes on the topic. Books published traditionally usually sell more copies.
Updates. You have the email addresses of your readers, and can send them updated versions of the book. No print edition. While you can print on demand with some services, like Kindle Direct Publishing, most people don’t put in that effort.

These pros and cons are for books. If you’re wondering about a breakdown of pros and cons specifically for self-published courses, they’re very similar because they face the same opportunities and challenges.

Should I create a book or course?

This is the big question. And while I wish I could give you a definitive answer one way or the other, it’s always going to be the same answer we love to give in tech: it depends.

Why would you want to self-publish a book or course? Here are some reasons:

  • Income: It’s nice to put something out there and have it generate an income as long as it’s available.
  • Positive impact: Creating a digital asset has high potential leverage. For example, if something takes you X amount of resources to create, and you distribute it to a thousand people who each gain Y amount of utility from learning with it, you’ve produced 1000 * Y utility in the world, which can be much larger than X. For more on this, I recommend Kleppmann’s post on the topic.
  • Reputation: Having written a book can help you get a job, gain clients, or simply elevate your reputation. Eve Porcello says publishing boosted her credibility—and as an added benefit, many readers hire her to teach workshops.
  • Knowledge: If you’re like me, you’ll find that you learn much more about the topic you’re writing about than you knew when you started. I know I certainly did—I finally read the GraphQL spec, learned Vue and Android, ran into and solved a ton of bugs, and went through countless blog posts and conference talks. 😄
  • Enjoyment: Some people enjoy the creative process. I liked learning, building example applications, and writing. In other words, there’s a level of self-fulfillment you can get from the work.

Those are the reasons why you might want to self-publish material. But whether you should actually do it depends on:

  • Your writing ability: You absolutely need to be good at explaining complex concepts in simple terms that are easy for anyone to grasp. That’s a seriously high bar, especially if there’s existing good content on the topic.
  • Your willingness to market: You need to be willing to get the word out, because no one will do it for you (at least at first). That takes some guts. I know there are many of people out there who have a tough time promoting themselves and their work.
  • What it’s worth to you: You’ve seen a lot of the benefits that self-publishing content can offer, but are they worth it to you? Do impact, knowledge, and reputation motivate you? Maybe none of that matters and you’re simply looking for a labor of love. Whatever your motivation is, it’s important. Without it, you could lose steam and wind up with an unfinished project.
  • The opportunity cost: What else would you do with your time and energy if you didn’t self-publish? Is that thing more valuable to you? Is there anything you’d regret missing out on because of this?

For me, while writing a book had an opportunity cost of lower income (compared to doing more consulting work), I’ve made a positive impact, increased my knowledge on a subject I care about, gained reputation, and enjoyed the process. And it also feels great when someone goes out of their way to tell me they’re “blown away” and appreciate reading my book. 😃🤗✨

Thanks to Chris Coyier, Geoff Graham, Sacha Greif, Robin Wieruch, Mandi Wise, Sebastian Grebe, Julian Mayorga, and Rachel Lake for providing input for this article.


The post So you want to self-publish books and courses on programming appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , ,
[Top]

Is CSS a Programming Language?

I have a real distaste for this question. It might seem like a fun question to dig into on the surface, but the way it enters public discourse rarely seems to be in good faith. There are ulterior motives at play involving respect, protective emotions, and desires to break or maintain the status quo.

If someone can somehow prove that CSS isn’t a programming language (this is such a gray area that if that was your goal, it wouldn’t be terribly hard to do) then they get to keep on feeling superior in their “real” programming skills and rationalize the fact that they are (likely) paid more than a front-of-the-front-ender specializing in CSS. This is maintaining the status quo.

The reverse can also be true. If you can prove that CSS is a programming language, perhaps you can shift your own company or the industry at large toward equal respect and pay toward front-of-the-front-end developers. This is breaking the status quo.

Let’s say we could all agree on a boolean true or false on if CSS is a programming language. What now? If true, is pay normalized among all web workers? If false, do CSS specialists deserve pay cuts? If true, does everyone start respecting each other in a way they don’t now? If false, do CSS people have to eat lunch in the boiler room? I have doubts that anything will change; hence my distaste for the discussion at all.

Whatever the facts, it’s unlikely most people are going to accept even the possibility that CSS is a programming language. I mean, programs execute, don’t they? Nobody doubts that JavaScript is a programming language, because it executes. You write code and then execute that code. Perhaps you open a terminal window and write:

> node my-program.js

Sure as eggs is eggs, that program will execute. You can make “Hello, World!” print to the terminal with console.log("Hello, World!");.

CSS can’t do that! Um, well, unless you write body::after { content: "Hello, World!"; } in style.css file and open a web page that loads that CSS file. So CSS does execute, in its own special way. It’s a domain-specific language (DSL) rather than a general-purpose language (GPL). In that browser context, the way CSS is told to run (<link>, usually) isn’t even that different from how JavaScript is told to run (<script>, usually).

If you’re looking for comparisons for CSS syntax to programming concepts, I think you’ll find them. What is a selector if not a type of if statement that runs a loop over matches? What is calc() if not a direct implementation of math? What is a group of media queries if not a switch? What is a custom property if not a place to store state? What is :checked if not boolean? Eric recently made the point that CSS is typed, and earlier, that CSS is chock full of functions.

For better or worse, having an answer to whether or not CSS is a programming language affects people. One college professor had made a point of telling students that CSS is not Turing complete, but is now re-considering that position upon learning that it is. Whatever the intention there, I think the industry is affected by what computer science professors tell computer science students year after year.

Lara Schenck has dug into the Turing-complete angle. If you’re trying to settle this, Turing completeness is a good proxy. It turns out that CSS basically is Turing complete (by settling the cellular automaton angle of Rule 110), just not entirely by itself. It involves a somewhat complex use of selectors and :checked (surprise, surprise). Lara makes an astute point:

Alone, CSS is not Turing complete. CSS plus HTML plus user input is Turing complete!

Still, say you don’t buy it. You get it and even concede, OK fine, CSS is essentially Turing complete, but it just doesn’t feel like CSS (or HTML for that matter) is a programming language to you. It’s too declarative. Too application-specific. Whatever it is, I honestly don’t blame you. What I hope is that whatever conclusion you come to, the answer doesn’t affect things that really matter1, like pay and respect.

Respect is in order, no matter what any of us come to for an answer. I don’t consider CSS a programming language, but it doesn’t mean I think it’s trivial or that my specialist co-workers are any less valuable than my Python specialist co-workers. Wouldn’t that be nice? I think there is an interesting distinction between declarative markup languages and other types of languages, but they are all code. Oh stop it, you know how thoughtful answers make me blush.

I’d like to see a lot more nuanced, respectful, and agenda-less comments like that when these discussions happen.


  1. Just like “website” vs “web app.” Whether or not you think there is a distinction, I would hope people aren’t making decisions that affect users based on what taxonomical bucket you think your thing goes in.

The post Is CSS a Programming Language? appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

,
[Top]

The Flavors of Object-Oriented Programming (in JavaScript)

In my research, I’ve found there are four approaches to Object-Oriented Programming in JavaScript:

Which methods should I use? Which one is “the best” way? Here I’ll present my findings along with information that may help you decide which is right for you.

To make that decision, we’re not just going to look at the different flavors but compare conceptual aspects between them:

What is Object-Oriented Programming?

Object-Oriented Programming is a way of writing code that allows you to create different objects from a common object. The common object is usually called a blueprint while the created objects are called instances.

Each instance has properties that are not shared with other instances. For example, if you have a Human blueprint, you can create human instances with different names.

The second aspect of Object-Oriented Programming is about structuring code when you have multiple levels of blueprints. This is commonly called Inheritance or subclassing.

The third aspect of Object Oriented Programming is about encapsulation where you hide certain pieces of information within the object so they’re not accessible.

If you need more than this brief intro, here’s an article that introduces this aspect of Object-Oriented Programming if you need help with it.

Let’s begin with the basics — an introduction to the four flavors of Object-Oriented Programming.

The four flavors of Object-Oriented Programming

There are four ways to write Object-Oriented Programming in JavaScript. They are:

Using Constructor functions

Constructors are functions that contain a this keyword.

function Human (firstName, lastName) {   this.firstName = firstName   this.lastName = lastName }

this lets you store (and access) unique values created for each instance. You can create an instance with the new keyword.

const chris = new Human('Chris', 'Coyier') console.log(chris.firstName) // Chris console.log(chris.lastName) // Coyier  const zell = new Human('Zell', 'Liew') console.log(zell.firstName) // Zell console.log(zell.lastName) // Liew

Class syntax

Classes are said to be the “syntactic sugar” of Constructor functions. As in, Classes are an easier way of writing Constructor functions.

There’s serious contention about whether Classes are bad (like this and this). We’re not going to dive into those arguments here. Instead, we’re just going to look at how to write code with Classes and decide whether Classes are better than constructors based on the code we write.

Classes can be written with the following syntax:

class Human {   constructor(firstName, lastName) {     this.firstName = firstName     this.lastName = lastName   } }

Notice the constructor function contains the same code as the Constructor syntax above? We need to do this since we want to initialize values into this. (We can skip constructor if we don’t need to initialize values. More on this later under Inheritance).

At first glance, classes seem to be inferior to constructors — there’s more code to write! Hold your horses and don’t form a conclusion at this point. We have a lot more to cover. Classes begin to shine later.

As before, you can create an instance with the new keyword.

const chris = new Human('Chris', 'Coyier')  console.log(chris.firstName) // Chris console.log(chris.lastName) // Coyier

Objects Linking to Other Objects (OLOO)

OLOO was coined and popularized by Kyle Simpson. In OLOO, you define the blueprint as a normal object. You then use a method (often named init, but that isn’t required in the way constructor is to a Class) to initialize the instance.

const Human = {   init () {     this.firstName = firstName     this.lastName = lastName   } }

You use Object.create to create an instance. After creating the instance, you need to run your init function.

const chris = Object.create(Human) chris.init('Chris', 'Coyier')  console.log(chris.firstName) // Chris console.log(chris.lastName) // Coyier

You can chain init after Object.create if you returned this inside init.

const Human = {   init () {     // ...     return this    } }  const chris = Object.create(Human).init('Chris', 'Coyier') console.log(chris.firstName) // Chris console.log(chris.lastName) // Coyier

Factory functions

Factory functions are functions that return an object. You can return any object. You can even return a Class instance or OLOO instance — and it’ll still be a valid Factory function.

Here’s the simplest way to create Factory functions:

function Human (firstName, lastName) {   return {     firstName,     lastName   } }

You don’t need new to create instances with Factory functions. You simply call the function.

const chris = Human('Chris', 'Coyier')  console.log(chris.firstName) // Chris console.log(chris.lastName) // Coyier

Now that we’ve seen these four OOP setup possibilities, let’s look at how you declare properties and methods on each of them so we can get a little better understanding of working with them before getting to the bigger comparisons we’re trying to make.


Declaring properties and methods

Methods are functions declared as an object’s property.

const someObject = {   someMethod () { /* ... */ } }

In Object-Oriented Programming, there are two ways to declare properties and methods:

  1. Directly on the instance
  2. In the Prototype

Let’s learn to do both.

Declaring properties and methods with Constructors

If you want to declare a property directly on an instance, you can write the property inside the constructor function. Make sure to set it as the property for this.

function Human (firstName, lastName) {   // Declares properties   this.firstName = firstName   this.lastname = lastName    // Declares methods   this.sayHello = function () {     console.log(`Hello, I'm $ {firstName}`)   } }  const chris = new Human('Chris', 'Coyier') console.log(chris)

Methods are commonly declared on the Prototype because Prototype allows instances to use the same method. It’s a smaller “code footprint.”

To declare properties on the Prototype, you need to use the prototype property.

function Human (firstName, lastName) {   this.firstName = firstName   this.lastname = lastName }  // Declaring method on a prototype Human.prototype.sayHello = function () {   console.log(`Hello, I'm $ {this.firstName}`) }

It can be clunky if you want to declare multiple methods in a Prototype.

// Declaring methods on a prototype Human.prototype.method1 = function () { /*...*/ } Human.prototype.method2 = function () { /*...*/ } Human.prototype.method3 = function () { /*...*/ }

You can make things easier by using merging functions like Object.assign.

Object.assign(Human.prototype, {   method1 () { /*...*/ },   method2 () { /*...*/ },   method3 () { /*...*/ } })

Object.assign does not support the merging of Getter and Setter functions. You need another tool. Here’s why. And here’s a tool I created to merge objects with Getters and Setters.

Declaring properties and methods with Classes

You can declare properties for each instance inside the constructor function.

class Human {   constructor (firstName, lastName) {     this.firstName = firstName       this.lastname = lastName        this.sayHello = function () {         console.log(`Hello, I'm $ {firstName}`)       }   } }

It’s easier to declare methods on the prototype. You write the method after constructor like a normal function.

class Human (firstName, lastName) {   constructor (firstName, lastName) { /* ... */ }    sayHello () {     console.log(`Hello, I'm $ {this.firstName}`)   } }

It’s easier to declare multiple methods on Classes compared to Constructors. You don’t need the Object.assign syntax. You just write more functions.

Note: there’s no , between method declarations in a Class.

class Human (firstName, lastName) {   constructor (firstName, lastName) { /* ... */ }    method1 () { /*...*/ }   method2 () { /*...*/ }   method3 () { /*...*/ } }

Declaring properties and methods with OLOO

You use the same process for declaring properties and methods on an instance. You assign them as a property of this.

const Human = {   init (firstName, lastName) {     this.firstName = firstName     this.lastName = lastName     this.sayHello = function () {       console.log(`Hello, I'm $ {firstName}`)     }      return this   } }  const chris = Object.create(Human).init('Chris', 'Coyier') console.log(chris)

To declare methods in the prototype, you write the method like a normal object.

const Human = {   init () { /*...*/ },   sayHello () {     console.log(`Hello, I'm $ {this.firstName}`)   } }

Declaring properties and methods with Factory functions

You can declare properties and methods directly by including them in the returned object.

function Human (firstName, lastName) {   return {     firstName,     lastName,      sayHello () {       console.log(`Hello, I'm $ {firstName}`)     }   } }

You cannot declare methods on the Prototype when you use Factory functions. If you really want methods on the prototype, you need to return a Constructor, Class, or OLOO instance. (Don’t do this since it doesn’t make any sense.)

// Do not do this function createHuman (...args) {   return new Human(...args) }

Where to declare properties and methods

Should you declare properties and methods directly on the instance? Or should you use prototype as much as you can?

Many people take pride that JavaScript is a “Prototypal Language” (which means it uses prototypes). From this statement, you may make the assumption that using “Prototypes” is better.

The real answer is: It doesn’t matter.

If you declare properties and methods on instances, each instance will take up slightly more memory. If you declare methods on Prototypes, the memory used by each instance will decrease, but not much. This difference is insignificant with computer processing power what it is today. Instead, you want to look at how easy it is to write code — and whether it is possible to use Prototypes in the first place.

For example, if you use Classes or OLOO, you’ll be better off using Prototypes since the code is easier to write. If you use Factory functions, you cannot use Prototypes. You can only create properties and methods directly on the instance.

I wrote a separate article on understanding JavaScript Prototypes if you’re interested in finding out more.

Preliminary verdict

We can make a few notes from the code we wrote above. These opinions are my own!

  1. Classes are better than Constructors because its easier to write multiple methods on Classes.
  2. OLOO is weird because of the Object.create part. I gave OLOO a run for a while, but I always forget to write Object.create. It’s weird enough for me not to use it.
  3. Classes and Factry Fufnctions are easiest to use. The problem is that Factory functions don’t support Prototypes. But like I said, this doesn’t really matter in production.

We’re down to two. Should we choose Classes or Factory functions then? Let’s compare them!


Classes vs. Factory functions — Inheritance

To continue the discussion on Classes and Factory functions, we need to understand three more concepts that are tied closely to Object-Oriented Programming.

  1. Inheritance
  2. Encapsulation
  3. this

Let’s start with Inheritance.

What is Inheritance?

Inheritance is a loaded word. Many people in the industry use Inheritance incorrectly, in my opinion. The word “inheritance” is used when you receive things from somewhere. For example:

  • If you get an inheritance from your parents, it means you get money and assets from them.
  • If you inherit genes from your parents, it means you get your genes from them.
  • If you inherit a process from your teacher, it means you get that process from them.

Fairly straightforward.

In JavaScript, Inheritance can mean the same thing: where you get properties and methods from the parent blueprint.

This means all instances actually inherit from their blueprints. They inherit properties and methods in two ways:

  1. by creating a property or method directly upon creating the instance
  2. via the Prototype chain

We discussed how to do both methods in the previous article so refer back to it if you need help seeing these processes in code.

There’s a second meaning for Inheritance in JavaScript — where you create a derivative blueprint from the parent blueprint. This process is more accurately called Subclassing, but people sometimes will call this Inheritance as well.

Understanding Subclassing

Subclassing is about creating a derivative blueprint from a common blueprint. You can use any Object-Oriented Programming flavor to create the Subclass.

We’ll talk about this with the Class syntax first because it’s easier to understand.

Subclassing with Class

When you create a Subclass, you use the extends keyword.

class Child extends Parent {   // ... Stuff goes here }

For example, let’s say we want to create a Developer class from a Human class.

// Human Class class Human {   constructor (firstName, lastName) {     this.firstName = firstName     this.lastName = lastName   }    sayHello () {     console.log(`Hello, I'm $ {this.firstName}`)   } }

The Developer class will extend Human like this:

class Developer extends Human {   constructor(firstName, lastName) {     super(firstName, lastName)   }      // Add other methods }

Note: super calls the Human (also called the “parent”) Class. It initiates the constructor from Human. If you don’t need extra initiation code, you can omit constructor entirely.

class Developer extends Human {   // Add other methods }

Let’s say a Developer can code. We can add the code method directly to Developer.

class Developer extends Human {   code (thing) {     console.log(`$ {this.firstName} coded $ {thing}`)   } }

Here’s an example of an instance of Developer:

const chris = new Developer('Chris', 'Coyier') console.log(chris)
Instance of a Developer class.

Subclassing with Factory functions

There are four steps to creating Subclasses with Factory functions:

  1. Create a new Factory function
  2. Create an instance of the Parent blueprint
  3. Create a new copy of this instance
  4. Add properties and methods to this new copy

The process looks like this:

function Subclass (...args) {   const instance = ParentClass(...args)   return Object.assign({}, instance, {     // Properties and methods go here   }) }

We’ll use the same example — creating a Developer Subclass — to illustrate this process. Here’s the Human factory function:

function Human (firstName, lastName) {   return {     firstName,     lastName,     sayHello () {       console.log(`Hello, I'm $ {firstName}`)     }   } }

We can create Developer like this:

function Developer (firstName, lastName) {   const human = Human(firstName, lastName)   return Object.assign({}, human, {     // Properties and methods go here   }) }

Then we add the code method like this:

function Developer (firstName, lastName) {   const human = Human(firstName, lastName)   return Object.assign({}, human, {     code (thing) {       console.log(`$ {this.firstName} coded $ {thing}`)     }   }) }

Here’s an example of a Developer instance :

const chris = Developer('Chris', 'Coyier') console.log(chris)
Example of a Developer instance with Factory functions.

Note: You cannot use Object.assign if you use Getters and Setters. You’ll need another tool, like mix. I explain why in this article.

Overwriting the Parent’s method

Sometimes you need to overwrite the Parent’s method inside the Subclass. You can do this by:

  1. Creating a method with the same name
  2. Calling the Parent’s method (optional)
  3. Changing whatever you need in the Subclass’s method

The process looks like this with Classes:

class Developer extends Human {   sayHello () {     // Calls the parent method     super.sayHello()       // Additional stuff to run     console.log(`I'm a developer.`)   } }  const chris = new Developer('Chris', 'Coyier') chris.sayHello()
Overwriting a parent's method.

The process looks like this with Factory functions:

function Developer (firstName, lastName) {   const human = Human(firstName, lastName)    return Object.assign({}, human, {       sayHello () {         // Calls the parent method         human.sayHello()           // Additional stuff to run         console.log(`I'm a developer.`)       }   }) }  const chris = new Developer('Chris', 'Coyier') chris.sayHello()
Overwriting a parent's method.

Inheritance vs. Composition

No talk about Inheritance ever concludes without the mention of Composition. Experts like Eric Elliot often suggests we should favor Composition over Inheritance.

“Favor object composition over class inheritance” the Gang of Four, “Design Patterns: Elements of Reusable Object Oriented Software”

“In computer science, a composite data type or compound data type is any data type which can be constructed in a program using the programming language’s primitive data types and other composite types. […] The act of constructing a composite type is known as composition.” ~ Wikipedia

So let’s give Composition a deeper look and understand what it is.

Understanding Composition

Composition is the act of combining two things into one. It’s about merging things together. The most common (and simplest) way of merging objects is with Object.assign.

const one = { one: 'one' } const two = { two: 'two' } const combined = Object.assign({}, one, two)

The use of Composition can be better explained with an example. Let’s say we already have two Subclasses, a Designer and Developer. Designers can design, while developers can code. Both designers and developers inherit from the Human class.

Here’s the code so far:

class Human {   constructor(firstName, lastName) {     this.firstName = firstName     this.lastName = lastName   }    sayHello () {     console.log(`Hello, I'm $ {this.firstName}`)   } }  class Designer extends Human {   design (thing) {     console.log(`$ {this.firstName} designed $ {thing}`)   } }  class Developer extends Designer {   code (thing) {     console.log(`$ {this.firstName} coded $ {thing}`)   } }

Now let’s say you want to create a third Subclass. This Subclass is a mix of a Designer and a Developer they — can design and code. Let’s call it DesignerDeveloper (or DeveloperDesigner, whichever you fancy).

How would you create the third Subclass?

We cannot extend Designer and Developer classes at the same time. This is impossible because we cannot decide which properties come first. This is often called The Diamond Problem.

Diamond problem.

The Diamond Problem can be easily solved if we do something like Object.assign – where we prioritize one object over the other. If we use the Object.assign approach, we may be able to extend classes like this. But this is not supported in JavaScript.

// Doesn't work class DesignerDeveloper extends Developer, Designer {   // ... }

So we need to rely on Composition.

Composition says: Instead of trying to create DesignerDeveloper via Subclassing, let’s create a new object that stores common features. We can then include these features whenever necessary.

In practice, it can look like this:

const skills = {   code (thing) { /* ... */ },   design (thing) { /* ... */ },   sayHello () { /* ... */ } }

We can then skip Human altogether and create three different classes based on their skills.

Here’s the code for DesignerDeveloper:

class DesignerDeveloper {   constructor (firstName, lastName) {     this.firstName = firstName     this.lastName = lastName      Object.assign(this, {       code: skills.code,       design: skills.design,       sayHello: skills.sayHello     })   } }  const chris = new DesignerDeveloper('Chris', 'Coyier') console.log(chris)
Composing methods into a class

You can do the same with Developer and Designer.

class Designer {   constructor (firstName, lastName) {     this.firstName = firstName     this.lastName = lastName       Object.assign(this, {       design: skills.design,       sayHello: skills.sayHello     })    } }  class Developer {   constructor (firstName, lastName) {     this.firstName = firstName     this.lastName = lastName       Object.assign(this, {       code: skills.code,       sayHello: skills.sayHello     })    } }

Did you notice we’re creating methods directly on the instance? This is just one option. We can still put methods into the Prototype, but I think the code looks clunky. (It’s as if we’re writing Constructor functions all over again.)

class DesignerDeveloper {   constructor (firstName, lastName) {     this.firstName = firstName     this.lastName = lastName   } }  Object.assign(DesignerDeveloper.prototype, {   code: skills.code,   design: skills.design,   sayHello: skills.sayHello })
Composition via Classes by putting methods into the Prototype.

Feel free to use whatever code structure you’re attracted to. The results are kinda the same anyway.

Composition with Factory Functions

Composition with Factory functions is essentially adding the shared methods into the returned object.

function DesignerDeveloper (firstName, lastName) {   return {     firstName,     lastName,         code: skills.code,     design: skills.design,     sayHello: skills.sayHello   } }
Composing methods into a factory function

Inheritance and Composition at the same time

Nobody says we can’t use Inheritance and Composition at the same time. We can!

Using the example we’ve ironed out so far, Designer, Developer, and DesignerDeveloper Humans are still humans. They can extend the Human object.

Here’s an example where we use both inheritance and composition with the class syntax.

class Human {   constructor (firstName, lastName) {     this.firstName = firstName     this.lastName = lastName   }    sayHello () {     console.log(`Hello, I'm $ {this.firstName}`)   } }  class DesignerDeveloper extends Human {} Object.assign(DesignerDeveloper.prototype, {   code: skills.code,   design: skills.design })
Subclassing and Composition at the same time.

And here’s the same thing with Factory functions:

function Human (firstName, lastName) {   return {     firstName,     lastName,     sayHello () {        console.log(`Hello, I'm $ {this.firstName}`)     }   } }  function DesignerDeveloper (firstName, lastName) {   const human = Human(firstName, lastName)   return Object.assign({}, human, {     code: skills.code,     design: skills.design   } }
Subclassing and Composition in Factory functions

Subclassing in the real world

One final point about Subclassing vs. Composition. Even though experts have pointed out that Composition is more flexible (and hence more useful), Subclassing still has its merits. Many things we use today are built with the Subclassing strategy.

For example: The click event we know and love is a MouseEvent. MouseEvent is a Subclass of a UIEvent, which in turn is a Subclass of Event.

MouseEvent is a subclass of UIEvent.

Another example: HTML Elements are Subclasses of Nodes. That’s why they can use all properties and methods of Nodes.

HTMLElement is a subclass of Node.

Preliminary verdict

Classes and Factory functions can both use Inheritance and Composition. Composition seems to be cleaner in Factory functions though, but that’s not a big win over Classes.

We’ll examine Classes and Factory Functions more in detail next.


Classes vs. Factory functions — Encapsulation

We’v looked at the four different Object-Oriented Programming flavors so far. Two of them — Classes and Factory functions — are easier to use compared to the rest.

But the questions remain: Which should you use? And why?

To continue the discussion on Classes and Factory functions, we need to understand three concepts that are tied closely to Object-Oriented Programming:

  1. Inheritance
  2. Encapsulation
  3. this

We just talked about Inheritance. Now let’s talk about Encapsulation.

Encapsulation

Encapsulation is a big word, but it has a simple meaning. Encapsulation is the act of enclosing one thing inside another thing so the thing inside doesn’t leak out. Think about storing water inside a bottle. The bottle prevents water from leaking out.

In JavaScript, we’re interested in enclosing variables (which can include functions) so these variables don’t leak out into the external scope. This means you need to understand scope to understand encapsulation. We’ll go through an explanation, but you can also use this article to beef up your knowledge regarding scopes.

Simple Encapsulation

The simplest form of Encapsulation is a block scope.

{   // Variables declared here won't leak out }

When you’re in the block, you can access variables that are declared outside the block.

const food = 'Hamburger'  {   console.log(food) }
Logs food from inside the blog. Result: Hamburger.

But when you’re outside the block, you cannot access variables that are declared inside the block.

{   const food = 'Hamburger' }  console.log(food)
Logs food from outside the blog. Results: Error.

Note: Variables declared with var don’t respect block scope. This is why I recommend you use let or const to declare variables.

Encapsulating with functions

Functions behave like block scopes. When you declare a variable inside a function, they cannot leak out of that function. This works for all variables, even those declared with var.

function sayFood () {   const food = 'Hamburger' }  sayFood() console.log(food)
Logs food from outside the function. Results: Error.

Likewise, when you’re inside the function, you can access variables that are declared outside of that function.

const food = 'Hamburger'  function sayFood () {   console.log(food) }   sayFood()
Logs food from inside the function. Result: Hamburger.

Functions can return a value. This returned value can be used later, outside the function.

function sayFood () {   return 'Hamburger' }  console.log(sayFood())
Logs return value from function. Result: Hamburger.

Closures

Closures are an advanced form of Encapsulation. They’re simply functions wrapped in functions.

// Here's a closure function outsideFunction () {   function insideFunction () { /* ...*/ } }

Variables declared in outsideFunction can be used in insideFunction.

function outsideFunction () {   const food = 'Hamburger'   console.log('Called outside')    return function insideFunction () {     console.log('Called inside')     console.log(food)   } }  // Calls `outsideFunction`, which returns `insideFunction` // Stores `insideFunction` as variable `fn` const fn = outsideFunction()   // Calls `insideFunction` fn()
Closure logs.

Encapsulation and Object-Oriented Programming

When you build objects, you want to make some properties publicly available (so people can use them). But you also want to keep some properties private (so others can’t break your implementation).

Let’s work through this with an example to make things clearer. Let’s say we have a Car blueprint. When we produce new cars, we fill each car up with 50 liters of fuel.

class Car {   constructor () {     this.fuel = 50   } }

Here we exposed the fuel property. Users can use fuel to get the amount of fuel left in their cars.

const car = new Car() console.log(car.fuel) // 50

Users can also use the fuel property to set any amount of fuel.

const car = new Car() car.fuel = 3000 console.log(car.fuel) // 3000

Let’s add a condition and say that each car has a maximum capacity of 100 liters. With this condition, we don’t want to let users set the fuel property freely because they may break the car.

There are two ways to do prevent users from setting fuel:

  1. Private by convention
  2. Real Private Members

Private by convention

In JavaScript, there’s a practice of prepending underscores to a variable name. This denotes the variable is private and should not be used.

class Car {   constructor () {     // Denotes that `_fuel` is private. Don't use it!     this._fuel = 50   } }

We often create methods to get and set this “private” _fuel variable.

class Car {   constructor () {      // Denotes that `_fuel` is private. Don't use it!     this._fuel = 50   }    getFuel () {     return this._fuel   }    setFuel (value) {     this._fuel = value     // Caps fuel at 100 liters     if (value > 100) this._fuel = 100   } }

Users should use the getFuel and setFuel methods to get and set fuel.

const car = new Car()  console.log(car.getFuel()) // 50   car.setFuel(3000) console.log(car.getFuel()) // 100 

But _fuel is not actually private. It is still a public variable. You can still access it, you can still use it, and you can still abuse it (even if the abusing part is an accident).

const car = new Car()  console.log(car.getFuel()) // 50   car._fuel = 3000 console.log(car.getFuel()) // 3000

We need to use real private variables if we want to completely prevent users from accessing them.

Real Private Members

Members here refer to variables, functions, and methods. It’s a collective term.

Private Members with Classes

Classes let you create private members by prepending # to the variable.

class Car {   constructor () {     this.#fuel = 50   } }

Unfortunately, you can’t use # directly inside a constructor function.

Error when declaring <code>#</code> directly in constructor function.

You need to declare the private variable outside the constructor first.

class Car {   // Declares private variable   #fuel    constructor () {     // Use private variable     this.#fuel = 50   } }

In this case, we can use a shorthand and declare#fuel upfront since we set fuel to 50.

class Car {   #fuel = 50 }

You cannot access #fuel outside Car. You’ll get an error.

const car = new Car() console.log(car.#fuel)
Cannot access #fuel.

You need methods (like getFuel or setFuel) to use the #fuel variable.

class Car {   #fuel = 50    getFuel () {     return this.#fuel   }    setFuel (value) {     this.#fuel = value     if (value > 100) this.#fuel = 100   } }  const car = new Car() console.log(car.getFuel()) // 50  car.setFuel(3000) console.log(car.getFuel()) // 100

Note: I prefer Getters and Setters instead of getFuel and setFuel. The syntax is easier to read.

class Car {   #fuel = 50    get fuel () {     return this.#fuel   }    set fuel (value) {     this.#fuel = value     if (value > 100) this.#fuel = 100   } }  const car = new Car() console.log(car.fuel) // 50  car.fuel = 3000 console.log(car.fuel) // 100

Private Members with Factory functions

Factory functions create Private Members automatically. You just need to declare a variable like normal. Users will not be able to get that variable anywhere else. This is because variables are function-scoped and hence encapsulated by default.

function Car () {   const fuel = 50  }  const car = new Car()  console.log(car.fuel) // undefined  console.log(fuel) // Error: `fuel` is not defined

We can create getter and setter functions to use this private fuel variable.

function Car () {   const fuel = 50     return {     get fuel () {        return fuel      },      set fuel (value) {       fuel = value        if (value > 100) fuel = 100     }   } }  const car = new Car() console.log(car.fuel) // 50  car.fuel = 3000 console.log(car.fuel) // 100

That’s it! Simple and easy!

Verdict for Encapsulation

Encapsulation with Factory functions are simpler and easier to understand. They rely on the scopes which are a big part of the JavaScript language.

Encapsulation with Classes, on the other hand, requires prepending # to the private variable. This can make things clunky.

We’ll look at the final concept — this to complete the comparison between Classes and Factory functions — in the next section.


Classes vs. Factory Functions — The this variable

this (ha!) is one of the main arguments against using Classes for Object-Oriented Programming. Why? Because this value changes depending on how it is used. It can be confusing for many developers (both new and experienced).

But the concept of this is relatively simple in reality. There are only six contexts in which you can use this. If you master these six contexts, you’ll have no problems using this.

The six contexts are:

  1. In a global context
  2. Inan object construction
  3. In an object property / method
  4. In a simple function
  5. In an arrow function
  6. In an event listener

I covered these six contexts in detail. Give it a read if you need help understanding this.

Note: Don’t shy away from learning to use this. It’s an important concept you need to understand if you intend on mastering JavaScript.

Come back to this article after you’ve solidified your knowledge on this. We’ll have a deeper discussion about using this in Classes and Factory functions.

Back yet? Good. Let’s go!

Using this in Classes

this refers to the instance when used in a Class. (It uses the “In an object property / method” context.) This is why you can set properties and methods on the instance inside the constructor function.

class Human {   constructor (firstName, lastName) {     this.firstName = firstName     this.lastName = lastName     console.log(this)   } }  const chris = new Human('Chris', 'Coyier')
<code>this</code> points to the instance

Using this in Constructor functions

If you use this inside a function and new to create an instance, this will refer to the instance. This is how a Constructor function is created.

function Human (firstName, lastName) {   this.firstName = firstName    this.lastName = lastName   console.log(this)   }  const chris = new Human('Chris', 'Coyier')
<code>this</code> points to the instance.

I mentioned Constructor functions because you can use this inside Factory functions. But this points to Window (or undefined if you use ES6 Modules, or a bundler like webpack).

// NOT a Constructor function because we did not create instances with the `new` keyword function Human (firstName, lastName) {   this.firstName = firstName    this.lastName = lastName   console.log(this)   }  const chris = Human('Chris', 'Coyier')
<code>this</code> points to Window.

Essentially, when you create a Factory function, you should not use this as if it’s a Constructor function. This is one small hiccup people experience with this. I wanted to highlight the problem and make it clear.

Using this in a Factory function

The correct way to use this in a Factory function is to use it “in an object property / method” context.

function Human (firstName, lastName) {   return {     firstName,     lastName,     sayThis () {       console.log(this)     }   } }  const chris = Human('Chris', 'Coyier') chris.sayThis()
<code>this</code> points to the instance.

Even though you can use this in Factory functions, you don’t need to use them. You can create a variable that points to the instance. Once you do this, you can use the variable instead of this. Here’s an example at work.

function Human (firstName, lastName) {   const human = {     firstName,     lastName,     sayHello() {       console.log(`Hi, I'm $ {human.firstName}`)     }   }    return human }  const chris = Human('Chris', 'Coyier') chris.sayHello()

human.firstName is clearer than this.firstName because human definitely points back to the instance. You know when you see the code.

If you’re used to JavaScript, you may also notice there’s no need to even write human.firstName in the first place! Just firstName is enough because firstName is in the lexical scope. (Read this article if you need help with scopes.)

function Human (firstName, lastName) {   const human = {     firstName,     lastName,     sayHello() {       console.log(`Hi, I'm $ {firstName}`)     }   }    return human }  const chris = Human('Chris', 'Coyier') chris.sayHello()
Runs <code>chris.sayHello</code>

What we covered so far is simple. It’s not easy to decide whether this is actually needed until we create a sufficiently complicated example. So let’s do that.

Detailed example

Here’s the setup. Let’s say we have a Human blueprint. This Human ha firstName and lastName properties, and a sayHello method.

We have a Developer blueprint that’s derived from Human. Developers can code, so they’ll have a code method. Developers also want to proclaim they’re developers, so we need to overwrite sayHello and add I'm a Developer to the console.

We’ll create this example with Classes and Factory functions. (We’ll make an example with this and an example without this for Factory functions).

The example with Classes

First, we have a Human blueprint. This Human has a firstName and lastName properties, as well as a sayHello method.

class Human {   constructor (firstName, lastName) {     this.firstName = firstName     this.lastname = lastName    }    sayHello () {     console.log(`Hello, I'm $ {this.firstName}`)   } }

We have a Developer blueprint that’s derived from Human. Developers can code, so they’ll have a code method.

class Developer extends Human {   code (thing) {     console.log(`$ {this.firstName} coded $ {thing}`)   } }

Developers also want to proclaim that they’re developers. We need to overwrite sayHello and add I'm a Developer to the console. We do this by calling Human‘s sayHello method. We can do this using super.

class Developer extends Human {   code (thing) {     console.log(`$ {this.firstName} coded $ {thing}`)   }    sayHello () {     super.sayHello()     console.log(`I'm a developer`)   } }

The example with Factory functions (with this)

Again, first, we have a Human blueprint. This Human has firstName and lastName properties, as well as a sayHello method.

function Human () {   return {     firstName,     lastName,     sayHello () {       console.log(`Hello, I'm $ {this.firstName}`)     }   } }

Next, we have a Developer blueprint that’s derived from Human. Developers can code, so they’ll have a code method.

function Developer (firstName, lastName) {   const human = Human(firstName, lastName)   return Object.assign({}, human, {     code (thing) {       console.log(`$ {this.firstName} coded $ {thing}`)     }   }) }

Developers also want to proclaim they’re developers. We need to overwrite sayHello and add I'm a Developer to the console.
We do this by calling Human‘s sayHello method. We can do this using the human instance.

function Developer (firstName, lastName) {   const human = Human(firstName, lastName)   return Object.assign({}, human, {     code (thing) {       console.log(`$ {this.firstName} coded $ {thing}`)     },      sayHello () {       human.sayHello()       console.log('I'm a developer')     }   }) }

The example with Factory functions (without this)

Here’s the full code using Factory functions (with this):

function Human (firstName, lastName) {   return {     firstName,     lastName,     sayHello () {       console.log(`Hello, I'm $ {this.firstName}`)     }   } }  function Developer (firstName, lastName) {   const human = Human(firstName, lastName)   return Object.assign({}, human, {     code (thing) {       console.log(`$ {this.firstName} coded $ {thing}`)     },      sayHello () {       human.sayHello()       console.log('I'm a developer')     }   }) }

Did you notice firstName is available within the lexical scope in both Human and Developer? This means we can omit this and use firstName directly in both blueprints.

function Human (firstName, lastName) {   return {     // ...     sayHello () {       console.log(`Hello, I'm $ {firstName}`)     }   } }  function Developer (firstName, lastName) {   // ...   return Object.assign({}, human, {     code (thing) {       console.log(`$ {firstName} coded $ {thing}`)     },      sayHello () { /* ... */ }   }) }

See that? This means you can safely omit this from your code when you use Factory functions.

Verdict for this

In simple terms, Classes require this while Factory functions don’t. I prefer Factory functions here because:

  1. The context of this can change (which can be confusing)
  2. The code written with factory functions is shorter and cleaner (since we can use encapsulated variables without writing this.#variable).

Next up is the last section where we build a simple component together with both Classes and Factory functions. You get to see how they differ and how to use event listeners with each flavolr.

Classes vs Factory functions — Event listeners

Most Object-Oriented Programming articles show you examples without event listeners. Those examples can be easier to understand, but they don’t reflect the work we do as frontend developers. The work we do requires event listeners — for a simple reason — because we need to build things that rely on user input.

Since event listeners change the context of this, they can make Classes troublesome to deal with. At the same time, they make Factory functions more appealing.

But that’s not really the case.

The change in this doesn’t matter if you know how to handle this in both Classes and Factory functions. Few articles cover this topic so I thought it would be good to complete this article with a simple component using Object-Oriented Programming flavors.

Building a counter

We’re going to build a simple counter in this article. We’ll use everything you learned in this article — including private variables.

Let’s say the counter contains two things:

  1. The count itself
  2. A button to increase the count

Here’s the simplest possible HTML for the counter:

<div class="counter">   <p>Count: <span>0</span>   <button>Increase Count</button> </div>

Building the Counter with Classes

To make things simple, we’ll ask users to find and pass the counter’s HTML into a Counter class.

class Counter () {   constructor (counter) {     // Do stuff    }  }  // Usage  const counter = new Counter(document.querySelector('.counter'))

We need to get two elements in the Counter class:

  1. The <span> that contains the count – we need to update this element when the count increases
  2. The <button> – we need to add an event listener to this element class
Counter () {   constructor (counter) {     this.countElement = counter.querySelector('span')     this.buttonElement = counter.querySelector('button')   } }

We’ll initialize a count variable and set it to what the countElement shows. We’ll use a private #count variable since the count shouldn’t be exposed elsewhere.

class Counter () {   #count   constructor (counter) {     // ...      this.#count = parseInt(countElement.textContent)   }  }

When a user clicks the <button>, we want to increase #count. We can do this with another method. We’ll name this method increaseCount.

class Counter () {   #count   constructor (counter) { /* ... */ }    increaseCount () {     this.#count = this.#count + 1   } }

Next, we need to update the DOM with the new #count. Let’s create a method called updateCount to do this. We will call updateCount from increaseCount:

class Counter () {   #count   constructor (counter) { /* ... */ }    increaseCount () {     this.#count = this.#count + 1     this.updateCount()   }    updateCount () {     this.countElement.textContent = this.#count   } }

We’re ready to add the event listener now.

Adding the event listener

We will add the event listener to the this.buttonElement. Unfortunately, we cannot use increaseCount as the callback straightaway. You’ll get an error if you try it.

class Counter () {   // ...    constructor (counter) {     // ...     this.buttonElement.addEventListener('click', this.increaseCount)   }    // Methods }
Error accessing #count because this doesn't point to the instance

You get an error because this points to buttonElement. (This is the event listener context.) You’ll see the buttonElement if you logged this into the console.

this points to the button element

We need to change the value of this back to the instance for increaseCount in order for things to work. There are two ways to do it:

  1. Use bind
  2. Use arrow functions

Most people use the first method (but the second one is easier).

Adding the event listener with bind

bind returns a new function. It lets you change this to the first argument that’s passed. People normally create event listeners by calling bind(this).

class Counter () {   // ...    constructor (counter) {     // ...     this.buttonElement.addEventListener('click', this.increaseCount.bind(this))   }    // ... }

This works, but it’s not very nice to read. It’s also not beginner-friendly because bind is seen as an advanced JavaScript function.

Arrow functions

The second way is to use arrow functions. Arrow functions work because it preserves the this value to the lexical context.

Most people write methods inside the arrow function callback, like this:

class Counter () {   // ...    constructor (counter) {     // ...     this.buttonElement.addEventListener('click', _ => {       this.increaseCount()     })   }    // Methods }

This works, but it is a long way around. There’s actually a shortcut.

You can create increaseCount with arrow functions. If you do this, the this value for increaseCount will be bound to the instance’s value straightaway.

So here’s the code you need:

class Counter () {   // ...    constructor (counter) {     // ...     this.buttonElement.addEventListener('click', this.increaseCount)   }    increaseCount = () => {     this.#count = this.#count + 1     this.updateCounter()   }    // ... }

The code

Here’s a complete version of the Class-based code (using arrow functions).

Creating the Counter with Factory functions

We’ll do the same thing here. We’ll get users to pass the Counter’s HTML into the Counter factory.

function Counter (counter) {   // ... }  const counter = Counter(document.querySelector('.counter'))

We need to get two elements from counter — the <span> and the <button>. We can use normal variables (without this) here because they are private variables already. We won’t expose them.

function Counter (counter) {   const countElement = counter.querySelector('span')   const buttonElement = counter.querySelector('button') }

We will initialize a count variable to the value that’s present in the HTML.

function Counter (counter) {   const countElement = counter.querySelector('span')   const buttonElement = counter.querySelector('button')    let count = parseInt(countElement.textContext) }

We will increase this count variable with an increaseCount method. You can choose to use a normal function here, but I like to create a method to keep things neat and tidy.

function Counter (counter) {   // ...    const counter = {     increaseCount () {       count = count + 1     }   } }

Finally, we will update the count with an updateCount method. We will also call updateCount from increaseCount.

function Counter (counter) {   // ...    const counter = {     increaseCount () {       count = count + 1       counter.updateCount()     }      updateCount () {       increaseCount()     }   } }

Notice I used counter.updateCount instead of this.updateCount? I like this because counter is clearer compared to this.I also do this because beginners can also make a mistake with this inside Factory functions (which I’ll cover later).

Adding event listeners

We can add event listeners to the buttonElement. When we do this, we can use counter.increaseCount as the callback straight away.

We can do this because we didn’t use this, so it doesn’t matter even if event listeners change the this value.

function Counter (counterElement) {   // Variables     // Methods   const counter = { /* ... */ }    // Event Listeners   buttonElement.addEventListener('click', counter.increaseCount) }

The this gotcha

You can use this in Factory functions. But you need to use this in a method context.

In the following example, if you call counter.increaseCount, JavaScript will also call counter.updateCount. This works because this points to the counter variable.

function Counter (counterElement) {   // Variables     // Methods   const counter = {     increaseCount() {       count = count + 1       this.updateCount()     }   }    // Event Listeners   buttonElement.addEventListener('click', counter.increaseCount) }

Unfortunately, the event listener wouldn’t work because the this value was changed. You’ll need the same treatment as Classes — with bind or arrow functions to — get the event listener working again.

And this leads me to the second gotcha.

Second this gotcha

If you use the Factory function syntax, you cannot create methods with arrow functions. This is because the methods are created in a simple function context.

function Counter (counterElement) {   // ...   const counter = {     // Do not do this.      // Doesn't work because `this` is `Window`     increaseCount: () => {       count = count + 1       this.updateCount()     }   }   // ... }

So, I highly suggest skipping this entirely if you use Factory functions. It’s much easier that way.

The code

Verdict for event listeners

Event listeners change the value of this, so we must be very careful about using the this value. If you use Classes, I recommend creating event listeners callbacks with arrow functions so you don’t have to use bind.

If you use Factory functions, I recommend skipping this entirely because it may confuse you. That’s it!


Conclusion

We talked about the four flavors of Object-Oriented Programming. They are:

  1. Constructor functions
  2. Classes
  3. OLOO
  4. Factory functions

First, we concluded that Classes and Factory functions are easier to use from a code-related point of view.

Second, we compared how to use Subclasses with Classes and Factory functions. Here, we see creating Subclasses is easier with Classes, but Composition is easier with Factory functions.

Third, we compared Encapsulation with Classes and Factory functions. Here, we see Encapsulation with Factory functions is natural — like JavaScript — while encapsulation with Classes requires you to add a # before variables.

Fourth, we compared the usage of this in Classes and Factory functions. I feel Factory functions win here because this can be ambiguous. Writing this.#privateVariable also creates longer code compared to using privateVariable itself.

Finally, in this article, we built a simple Counter with both Classes and Factory functions. You learned how to add event listeners to both Object-Oriented Programming programming flavors. Here, both flavors work. You just need to be careful whether you use this or not.

That’s it!

I hope this shines some light on Object-Oriented Programming in JavaScript for you. If you liked this article, you may like my JavaScript course, Learn JavaScript, where I explain (almost) everything you need to know about JavaScript in a format as clear and succinct as this.

If you have any questions on JavaScript or front-end development in general, feel free to reach out to me. I’ll see how I can help!


The post The Flavors of Object-Oriented Programming (in JavaScript) appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , ,
[Top]

Programming Sass to Create Accessible Color Combinations

We’re all looking for low-hanging fruit to make our sites and apps more accessible. One of the easier things we can do is make sure the colors we use are easy on the eyes. High color contrast is something that benefits everyone. It not only reduces eye strain in general, but is crucial for folks who deal with reduced vision.

So let’s not only use better color combinations in our designs but find a way to make it easier for us to implement high contrasts. There’s one specific strategy we use over at Oomph that lets a Sass function do all the heavy lifting for us. I’ll walk you through how we put that together.

Want to jump right to the code because you already understand everything there is to know about color accessibility? Here you go.

What we mean by “accessible color combinations”

Color contrast is also one of those things we may think we have handled. But there’s more to high color contrasts than eyeballing a design. There are different levels of acceptable criteria that the WCAG has defined as being accessible. It’s actually humbling to crack open the WebAIM Contrast Checker and run a site’s color combinations through it.

My team adheres to WCAG’s Level AA guidelines by default. This means that: 

  • Text that is 24px and larger, or 19px and larger if bold, should have a Color Contrast Ratio (CCR) of 3.0:1.
  • Text that is smaller than 24px should have a CCR of 4.5:1.

If a site needs to adhere to the enhanced guidelines for Level AAA, the requirements are a little higher:

  • Text that is 24px and larger, or 19px and larger if bold, should have a CCR of 4.5:1.
  • Text that is smaller than 24px should have a CCR of 7:1.

Ratios? Huh? Yeah, there’s some math involved here. But the good news is that we don’t need to do it ourselves or even have the same thorough understanding about how they’re calculated the way Stacie Arellano recently shared (which is a must read if you’re into the science of color accessibility).

That’s where Sass comes in. We can leverage it to run difficult mathematical computations that would otherwise fly over many of our heads. But first, I think it’s worth dealing with accessible colors at the design level.

Accessible color palettes start with the designs

That’s correct. The core of the work of creating an accessible color palette starts with the designs. Ideally, any web design ought to consult a tool to verify that any color combinations in use pass the established guidelines — and then tweak the colors that don’t. When our design team does this, they use a tool that we developed internally. It works on a list of colors, testing them over a dark and a light color, as well as providing a way to test other combinations. 

ColorCube provides an overview of an entire color palette, showing how each color performs when paired with white, black, and even each other. It even displays results for WCAG Levels AA and AAA next to each result. The tool was designed to throw a lot of information at the user all at once when evaluating a list of colors.

This is the first thing our team does. I’d venture to guess that many brand colors aren’t chosen with accessibility at the forefront. I often find that those colors need to change when they get translated to a web design. Through education, conversation, and visual samples, we get the client to sign off on the new color palette. I’ll admit: that part can be harder than the actual work of implementing accessible colors combinations.

The Color Contrast Audit: A typical design delivery when working with an existing brand’s color palette. Here, we suggest to stop using the brand color Emerald with white, but use an “Alt” version that is slightly darker instead. 

The problem that I wanted to solve with automation are the edge cases. You can’t fault a designer for missing some instance where two colors combine in an unintended way — it just happens. And those edge cases will come up, whether it is during the build or even a year later when new colors are added to the system.

Developing for accessibility while keeping true to the intent of a color system

The trick when changing colors to meet accessibility requirements is not changing them so much that they don’t look like the same color anymore. A brand that loves its emerald green color is going to want to maintain the intent of that color — it’s “emerald-ness.” To make it pass for accessibility when it is used as text over a white background, we might have to darken the green and increase its saturation. But we still want the color to “read” the same as the original color.

To achieve this, we use the Hue Saturation Lightness (HSL) color model. HSL gives us the ability to keep the hue as it is but adjust the saturation (i.e. increase or decrease color) and lightness (i.e. add more black or more white). The hue is what makes a green that green, or a blue that blue. It is the “soul” of the color, to get a little mystical about it. 

Hue is represented as a color wheel with a value between 0° and 360° — yellow at 60°, green at 120°, cyan at 180°, etc. Saturation is a percentage ranging from 0% (no saturation) to 100% (full saturation). Lightness is also a value that goes from 0% to 100%, where no lightness is at 0%, no black and no white is at 50%, and 100% is all lightness, or very light.

A quick visual of what tweaking a color looks like in our tool:

With HSL, changing the low-contrast green to a higher contrast meant changing the saturation from 63 to 95 and the lightness from 45 to 26 on the left. That’s when the color gets a green check mark in the middle when used with white. The new green still feels like it is in the same family, though, because the Hue remained at 136, which is like the color’s “soul.”

To learn more, play around with the fun HSL visualizer mothereffinghsl.com. But for a more in-depth description of color blindness, WCAG color contrast levels, and the HSL color space, we wrote an in-depth blog post about it.

The use case I want to solve

Designers can adjust colors with the tools that we just reviewed, but so far, no Sass that I have found could do it with mathematical magic. There had to be a way. 

These are some similar approaches I have seen in the wild:

  • An idea by Josh Bader uses CSS variables and colors split into their RGB values to calculate whether white or black is the best accessible color to use in a given situation.
  • Another idea by Facundo Corradini does something similar with HSL values and a very cool “switch function” in CSS.

I didn’t like these approaches. I didn’t want to fallback to white or black. I wanted colors to be maintained but adjusted to be accessible. Additionally, changing colors to their RGB or HSL components and storing them with CSS variables seemed messy and unsustainable for a large codebase.

I wanted to use a preprocessor like Sass to do this: given two colors, automagically adjust one of them so the pair receives a passing WCAG grade. The rules state a few other things to consider as well — size of the text and whether or not the font is bold. The solution had to take this into account. 

In code terms, I wanted to do this:

// Transform this non-passing color pair: .example {   background-color: #444;   color: #0094c2; // a 2.79 contrast ratio when AA requires 4.5   font-size: 1.25rem;   font-weight: normal; } 
 // To this passing color pair: .example {   background-color: #444;   color: #00c0fc; // a 4.61 contrast ratio   font-size: 1.25rem;   font-weight: normal; }

A solution that does this would be able to catch and handle those edge cases we mentioned earlier. Maybe the designer accounted for a brand blue to be used over a light blue, but not a light gray. Maybe the red used in error messages needs to be tweaked for this one form that has a one-off background color. Maybe we want to implement a dark mode feature to the UI without having to retest all the colors again. These are the use cases I had in mind going into this. 

With formulas can come automation

The W3C has provided the community with formulas that help analyze two colors used together. The formula multiplies the RGB channels of both colors by magic numbers (a visual weight based on how humans perceive these color channels) and then divides them to come up with a ratio from 0.0 (no contrast) to 21.0 (all the contrast, only possible with white and black). While imperfect, this is the formula we use right now:

If L1 is the relative luminance of a first color  And L2 is the relative luminance of a second color, then - Color Contrast Ratio = (L1 + 0.05) / (L2 + 0.05) Where - L = 0.2126 * R + 0.7152 * G + 0.0722 * B And - if R sRGB <= 0.03928 then R = R sRGB /12.92 else R = ((R sRGB +0.055)/1.055) ^ 2.4 - if G sRGB <= 0.03928 then G = G sRGB /12.92 else G = ((G sRGB +0.055)/1.055) ^ 2.4 - if B sRGB <= 0.03928 then B = B sRGB /12.92 else B = ((B sRGB +0.055)/1.055) ^ 2.4 And - R sRGB = R 8bit /255 - G sRGB = G 8bit /255 - B sRGB = B 8bit /255

While the formula looks complex, it’s just math right? Well, not so fast. There is a part at the end of a few lines where the value is multiplied by a decimal power — raised to the power of 2.4. Notice that? Turns out that it’s complex math which most programming languages can accomplish — think Javascript’s math.pow() function — but Sass is not powerful enough to do it. 

There’s got to be another way…

Of course there is. It just took some time to find it. 🙂

My first version used a complex series of math calculations that did the work of decimal powers within the limited confines of what Sass can accomplish. Lots of Googling found folks much smarter than me supplying the functions. Unfortunately, calculating only a handful of color contrast combinations increased Sass build times exponentially. So, that means Sass can do it, but that does not mean it should. In production, build times for a large codebase could increase to several minutes. That’s not acceptable. 

After more Googling, I came across a post from someone who was trying to do a similar thing. They also ran into the lack of exponent support in Sass. They wanted to explore “the possibility of using Newtonian approximation for the fractional parts of the exponent.” I totally understand the impulse (not). Instead, they decided to use a “lookup table.” It’s a genius solution. Rather than doing the math from scratch every time, a lookup table provides all the possible answers pre-calculated. The Sass function retrieves the answer from the list and it’s done.

In their words:

The only part [of the Sass that] involves exponentiation is the per-channel color space conversions done as part of the luminance calculation. [T]here are only 256 possible values for each channel. This means that we can easily create a lookup table.

Now we’re cooking. I had found a more performant direction. 

Usage example

Using the function should be easy and flexible. Given a set of two colors, adjust the first color so it passes the correct contrast value for the given WCAG level when used with the second color. Optional parameters will also take the font size or boldness into account.

// @function a11y-color( //   $ color-to-adjust, //   $ color-that-will-stay-the-same, //   $ wcag-level: 'AA', //   $ font-size: 16, //   $ bold: false // ); 
 // Sass sample usage declaring only what is required .example {   background-color: #444;   color: a11y-color(#0094c2, #444); // a 2.79 contrast ratio when AA requires 4.5 for small text that is not bold } 
 // Compiled CSS results: .example {   background-color: #444;   color: #00c0fc; // which is a 4.61 contrast ratio }

I used a function instead of a mixin because I preferred the output of a single value independent from a CSS rule. With a function, the author can determine which color should change. 

An example with more parameters in place looks like this:

// Sass .example-2 {   background-color: a11y-color(#0094c2, #f0f0f0, 'AAA', 1.25rem, true); // a 3.06 contrast ratio when AAA requires 4.5 for text 19px or larger that is also bold   color: #f0f0f0;   font-size: 1.25rem;   font-weight: bold; } 
 // Compiled CSS results: .example-2 {   background-color: #087597; // a 4.6 contrast ratio   color: #f0f0f0;   font-size: 1.25rem;   font-weight: bold; }

A deeper dive into the heart of the Sass function

To explain the approach, let’s walk through what the final function is doing, line by line. There are lots of helper functions along the way, but the comments and logic in the core function explain the approach:

// Expected: // $ fg as a color that will change // $ bg as a color that will be static and not change // Optional: // $ level, default 'AA'. 'AAA' also accepted // $ size, default 16. PX expected, EM and REM allowed // $ bold, boolean, default false. Whether or not the font is currently bold // @function a11y-color($ fg, $ bg, $ level: 'AA', $ size: 16, $ bold: false) {   // Helper: make sure the font size value is acceptable   $ font-size: validate-font-size($ size);   // Helper: With the level, font size, and bold boolean, return the proper target ratio. 3.0, 4.5, or 7.0 results expected   $ ratio: get-ratio($ level, $ font-size, $ bold);   // Calculate the first contrast ratio of the given pair   $ original-contrast: color-contrast($ fg, $ bg);      @if $ original-contrast >= $ ratio {     // If we pass the ratio already, return the original color     @return $ fg;   } @else {     // Doesn't pass. Time to get to work     // Should the color be lightened or darkened?     // Helper: Single color input, 'light' or 'dark' as output     $ fg-lod: light-or-dark($ fg);     $ bg-lod: light-or-dark($ bg); 
     // Set a "step" value to lighten or darken a color     // Note: Higher percentage steps means faster compile time, but we might overstep the required threshold too far with something higher than 5%     $ step: 2%;          // Run through some cases where we want to darken, or use a negative step value     @if $ fg-lod == 'light' and $ bg-lod == 'light' {       // Both are light colors, darken the fg (make the step value negative)       $ step: - $ step;     } @else if $ fg-lod == 'dark' and $ bg-lod == 'light' {       // bg is light, fg is dark but does not pass, darken more       $ step: - $ step;     }     // Keeping the rest of the logic here, but our default values do not change, so this logic is not needed     //@else if $ fg-lod == 'light' and $ bg-lod == 'dark' {     //  // bg is dark, fg is light but does not pass, lighten further     //  $ step: $ step;     //} @else if $ fg-lod == 'dark' and $ bg-lod == 'dark' {     //  // Both are dark, so lighten the fg     //  $ step: $ step;     //}          // The magic happens here     // Loop through with a @while statement until the color combination passes our required ratio. Scale the color by our step value until the expression is false     // This might loop 100 times or more depending on the colors     @while color-contrast($ fg, $ bg) < $ ratio {       // Moving the lightness is most effective, but also moving the saturation by a little bit is nice and helps maintain the "power" of the color       $ fg: scale-color($ fg, $ lightness: $ step, $ saturation: $ step/2);     }     @return $ fg;   } }

The final Sass file

Here’s the entire set of functions! Open this in CodePen to edit the color variables at the top of the file and see the adjustments that the Sass makes:

All helper functions are there as well as the 256-line lookup table. Lots of comments should help folks understand what is going on. 

When an edge case has been encountered, a version in SassMeister with debug output was helpful while I was developing it to see what might be happening. (I changed the main function to a mixin so I can debug the output.) Feel free to poke around at this as well.

Play with this gist on SassMeister.

And finally, the functions have been stripped out of CodePen and put into a GitHub repo. Drop issues into the queue if you run into problems. 

Cool code! But can I use this in production?

Maybe. 

I’d like to say yes, but I’ve been iterating on this thorny problem for a while now. I feel confident in this code but would love more input. Use it on a small project and kick the tires. Let me know how the build time performs. Let me know if you come across edge cases where passing color values are not being supplied. Submit issues to the GutHub repo. Suggest improvements based on other code you’ve seen in the wild. 

I’d love to say that I have Automated All the A11y Things, but I also know it needs to be road-tested before it can be called Production Ready™. I’m excited to introduce it to the world. Thanks for reading and I hope to hear how you are using it real soon.

The post Programming Sass to Create Accessible Color Combinations appeared first on CSS-Tricks.

CSS-Tricks

, , , , ,
[Top]

Why do we have different programming languages?

“But why do I have to learn Python?” She wailed, “I like Scratch!”

“I know,” I said, “But there are different programming languages for different sorts of tasks.”

“That’s stupid” she said

I can empathize with the little girl in Terence Eden’s story. In high school, I got super into Turbo Pascal. I felt like I could do a lot of stuff in it. Then I went to college. The first course I took was Java and the second was Assembly. I remember feeling so resentful. Why couldn’t I just program in the language I already felt comfortable with? I spent four years feeling that way and then changed majors. I’m a little more adventurous now with my language galavanting, but not terribly.

The answer to why we have different programming languages is because they do different things to some degree. There are indeed cases where something could have written the same way in multiple languages, and you picked the one that you prefer.

The real answer is that some programming nerd (in the most endearing way) thought they could make a better language that (likely) reflects modern needs and styles. So they did and convinced a bunch of other nerds that it was a good idea, allowing the language to gained steam. It’s a miracle of sorts.

We don’t see it on the client-side web because it would probably be easier to colonize Mars than get all the major browsers to ship an entirely new language. The web sees innovation through slow evolution and at the framework level.

Direct Link to ArticlePermalink

The post Why do we have different programming languages? appeared first on CSS-Tricks.

CSS-Tricks

, ,
[Top]