How to implement visitor pattern in javascript?

Jan Turoň picture Jan Turoň · Mar 22, 2012 · Viewed 7.8k times · Source

As far as I understand, visitor pattern is often used to add methods to some hierarchy structure. But I still don't get it: see the example where I try to highlight left subtree:

subtree highlighting

Javascript tree implementation:

  function node(val) {
    this.value = val;
    this.left = this.right = null;
  }

  var tree = new node("A");
  tree.left = new node("B1");
  tree.right = new node("B2");
  tree.left.left = new node("C1");
  tree.left.right = new node("C2");

I think I am using visitor pattern highlighting:

node.prototype.accept = function(visitorObj) {
  visitorObj.visit(this);
}

function visitor() {
  var that = this;
  this.visit = function(tgt) {
    tgt.value = "*"+tgt.value;
  }
  this.highlight = function(tgt) {
    tgt.accept(that);
    if(tgt.left) that.highlight(tgt.left);
    if(tgt.right) that.highlight(tgt.right);
  }
}

(new visitor()).highlight(tree.left);

But why to use accept-visit methods, when it can be more straightforward?

function visitor() {
  var that = this;
  this.highlight = function(tgt) {
    tgt.value = "*"+tgt.value;
    if(tgt.left) that.highlight(tgt.left);
    if(tgt.right) that.highlight(tgt.right);
  }
}

(new visitor()).highlight(tree.left);

It is similar to this example. Does it mean that if language mix types (like javascript), there is no reason for accept-visit pair at all?

Answer

Udi Cohen picture Udi Cohen · Mar 22, 2012

You missed something in the implementation. Imagine that the left and the right properties of the Node element were private. Then how would you highlight them in your implementation?

The visitor should not be aware of the tree structure and let the node element run the visitor on any sub-element which is a direct child. So your code should look like this:

node.prototype.accept = function(visitorObj) {
    visitorObj.visit(this);
    if (this.left) this.left.accept(visitorObj);
    if (this.right) this.right.accept(visitorObj);
}

function visitor() {
    var that = this;
    this.visit = function(tgt) {
        tgt.value = "*"+tgt.value;
    }
    this.highlight = function(tgt) {
        tgt.accept(that);
    }
}

(new visitor()).highlight(tree.left);

This way the visitor has no knowledge of the structure of the tree, it is generic and will work on any node that has the property "value".