Attempting a Strategy design pattern in JS I'm going through the Head First Design Patterns book and I want to check whether I'm understanding some aspects of the first chapter. Does the code below program correctly to interfaces, encapsulate changeable behavior, and employ composition in a reasonable manner?

// trying to enforce some design pattern habits

// create a duck, that prints a line to the page as text
class DuckAbilities {
    constructor() {
        this.flying = new FlyBehavior()
    }
    addToPage() {
        this.statement = document.createElement("p")
        this.statement.innerHTML=this.flying.fly()
        document.body.append(this.statement)
    }
}
//interface for behaviors
class FlyBehavior {
    fly() {
        null
    }
 }

class DoesFly{
    fly() {
        return "I'm flying"
    }
}
class DoesNotFly {
    fly() {
        return "not flying"
    }
}

class Mallard {
    constructor() {
        this.abilities = new DuckAbilities()
        this.abilities.flying = new DoesFly()
    }

}

class Rubber{
    constructor() {
        this.abilities = new DuckAbilities()
        this.abilities.flying = new DoesNotFly()
    }
}


window.onload = ()=&gt; {
    let mallard = new Mallard()
    mallard.abilities.addToPage()
    let rubber = new Rubber()
    rubber.abilities.addToPage()
}
There are some issues with your class, but I don't think that they are so specific to implementing a strategy pattern.

addToPage() {
    this.statement = document.createElement("p")
    this.statement.innerHTML=this.flying.fly()
    document.body.append(this.statement)
}


This assumes there is a global document variable, and that statement is part of the abilities object. If such a method is present, I would expect document to be a parameter of the method and statement to be a local variable. But even that doesn't seem right because you would be mixing representation (a paragraph "p") and a data class.

//interface for behaviors
class FlyBehavior {
    fly() {
        null
    }
 }


Now that doesn't seem right. If you have JS ducktyping then you don't need this class. Furthermore, specifying null is just asking for null pointer exceptions at a later stage.

this.abilities = new DuckAbilities()


OK, so now we have DuckAbilities object but without a valid state, just null, which we then adjust in the next call. There seem to be two ways of resolving this issue:


having the fying behavior as parameter to the DuckAbilities constructor;
removing the DuckAbilities altogether and just assigning the various flybehaviors to a field.




So when we're using classes anyway, lets implement it using those.

I've created an "abstract" class Duck because we require inheritance there. I don't like to create an interface for the strategies because JavaScripts duck-typing should be sufficient.

'use strict'

class Duck { // this is the context
    constructor(flyAbility) {
        // ES2015 only, avoid instantiation of Duck directly
        // if (new.target === Abstract) {
        //  throw new TypeError("Cannot construct Abstract instances directly");
        // }

        this.flyAbility = flyAbility;
    }

    // this is the operation, returning the flyBehavior as a string
    showFlyBehavior() {
        return "This duck " + this.flyAbility.flyBehavior();
    }
}

// Strategy interface is missing due to JS ducktyping

// Strategy #1 
class DoesFly {
    // with algorithm #1
    flyBehavior() {
        return "flies";
    }
}

// Strategy #2
class DoesNotFly {
    // with algorithm #2
    flyBehavior() {
        return "doesn't fly";
    }
}

// Context #1
class Mallard extends Duck {
    constructor() {
        super(new DoesFly());
    }
}

// Context #2
class Rubber extends Duck {
    constructor() {
        super(new DoesNotFly());
    }
}

let duck = new Mallard();
console.log(duck.showFlyBehavior());

duck = new Rubber();
console.log(duck.showFlyBehavior());


Sorry about using NodeJS, but in principle only console.log is NodeJS specific ... I hope.