Duck-punching the prototype

9 Apr 2018 · by David DeSandro

Every so often I encounter an issue with a Metafizzy plugin that I can't resolve its standard API. The only way to get it done is to overwrite core plugin code. These issues call for duck-punching. Paul Irish's post on duck-punching jQuery is a great overview.

Duck-punching is another name for monkey patching. Monkey patching is a technique to “extend or modify the runtime code of dynamic languages without altering the original source code.”

Let's say you want to add a class is-animating to Flickity when it is animating. Flickity does not have a startAnimation event. But it does have a startAnimation method on its prototype. We can duck-punch that method to add our desired behavior.

// get original method
var startAnimation = Flickity.prototype.startAnimation;
// overwrite method
Flickity.prototype.startAnimation = function() {
  // call original method
  startAnimation.apply( this, arguments );
  // do new stuff
  this.element.classList.add('is-animating');
};

Let's break down what's happening here:

  • Store the original method as a variable.
  • Overwrite the method.
  • Within the new method, trigger the original behavior by calling the stored method with apply(). Pass in this and arguments to set instance and any arguments.
  • Add new behavior within the method.

Likewise, we can duck-punch the _create method to add an event listener on settle to remove the class.

// get original method
var _create = Flickity.prototype._create;
// overwrite method
Flickity.prototype._create = function() {
  // call original method
  _create.apply( this, arguments );
  // do new stuff
  this.on( 'settle', function() {
    this.element.classList.remove('is-animating');
  });
};

Here's a demo with these two duck-punches:

View Flickity - duck punches CodePen

By duck-punching prototype methods, we change the behavior of all Flickity instances. If you want to change behavior on individual instances, you can do so by duck-punching instance methods.

// create new instance
var flkty = new Flickity('.carousel');

// get original method
var startAnimation = flkty.startAnimation;
// overwrite method
flkty.startAnimation = function() {
  // call original method
  startAnimation.apply( this, arguments );
  // do new stuff
  console.log('start animation');
};

Duck-punching is a nice way to mess around with Metafizzy plugins without overhauling internal code. It's great for debugging, allowing you to shim in console.log like in the example above.

Duck-punching is one of those quirky features of JavaScript. At first it looks like a gross hack, but its usefulness makes it a thing of ugly beauty.