1

When testing a JS example of a binary tree generation and traversal code, I replaced the print() with a console.log() to create console output. An "Uncaught...Illegal invocation" is thrown at 'case "this": func(this.value);'. Why can't this function be passed as a function parameter like any other? As you can see from the commented code, passing the "tree" object to console.log just outputs the function code, not the .value. Can anyone provide guidance on the circumstances of this exception or a better way to log test output?

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script type="text/javascript">
        //20140122-this example code originally had "print" statements in place of console.log, however, console.log cannot be passed as a function parameter.

        function BinaryTree(value, left, right) {
            this.value = value;
            this.left = left;
            this.right = right;
        }

        BinaryTree.prototype.preorder = function(f) { this.walk(f, ['this', 'left', 'right']); };
        BinaryTree.prototype.inorder = function(f) { this.walk(f, ['left', 'this', 'right']); };
        BinaryTree.prototype.postorder = function(f) { this.walk(f, ['left', 'right', 'this']); };
        BinaryTree.prototype.walk = function(func, order) {
            for (var i in order)
                switch (order[i]) {
                case "this":
                    func(this.value);
                    break;
                case "left":
                    if (this.left) this.left.walk(func, order);
                    break;
                case "right":
                    if (this.right) this.right.walk(func, order);
                    break;
                }
        };
        BinaryTree.prototype.levelorder = function(func) {
            var queue = [this];
            while (queue.length != 0) {
                var node = queue.shift();
                func(node.value);
                if (node.left) queue.push(node.left);
                if (node.right) queue.push(node.right);
            }
        };

        // convenience function for creating a binary tree
        function createBinaryTreeFromArray(ary) {
            var left = null, right = null;
            if (ary[1]) left = createBinaryTreeFromArray(ary[1]);
            if (ary[2]) right = createBinaryTreeFromArray(ary[2]);
            return new BinaryTree(ary[0], left, right);
        }

        var tree = createBinaryTreeFromArray([1, [2, [4, [7]], [5]], [3, [6, [8], [9]]]]);

        console.log("*** preorder ***"); tree.preorder(console.log);
        console.log("*** inorder ***"); tree.inorder(console.log);
        console.log("*** postorder ***"); tree.postorder(console.log);
        console.log("*** levelorder ***"); tree.levelorder(console.log);
//        console.log("*** preorder ***"); console.log(tree.preorder);
//        console.log("*** inorder ***"); console.log(tree.inorder);
//        console.log("*** postorder ***"); console.log(tree.postorder);
//        console.log("*** levelorder ***"); console.log(tree.levelorder);
//    </script>
</head>
<body>
</body>
</html>
robWDC
  • 139
  • 1
  • 2
  • 13

1 Answers1

3

When you pass a method of an object as parameter to a function you lose the context. To keep it, simply bind the method to the context:

tree.levelorder(console.log.bind(console));

Ex:

[1,2,3].forEach(console.log)
> TypeError: Illegal invocation

[1,2,3].forEach(console.log.bind(console))
> 1 0 [1, 2, 3]
> 2 1 [1, 2, 3]
> 3 2 [1, 2, 3] 
Tibos
  • 27,507
  • 4
  • 50
  • 64