I wrote a simple Sudoku solver using backtracking in JS. In effort to be "purely functional" all my 9x9 puzzle arrays are immutable thus a new array is created whenever a new number is inserted.
Version 1 using new SudokuPuzzle
In the first version I use the new Puzzle(puzzle)
approach to clone the object:
function SudokuPuzzle(obj) {
if (obj instanceof SudokuPuzzle) {
this.grid = obj.grid.slice(0); // copy array
} // ...
}
Then whenever I update the array I do the following:
SudokuPuzzle.prototype.update = function(row, col, num) {
var puzzle = new SudokuPuzzle(this); // clone puzzle
puzzle.grid[row*9 + col] = num; // mutate clone
return puzzle; // return clone
}
Version 2 using Object.create()
I wrote another version where I use Object.create()
instead and have a base object sudokuPuzzle
that I inherit from to create new puzzles. Here is the clone()
method:
sudokuPuzzle.clone = function() {
var puzzle = Object.create(this); // create puzzle from sudokuPuzzle
puzzle.grid = this.grid.slice(0); // copy array
return puzzle; // return newly minted puzzle
}
My update method in this case is
sudokuPuzzle.update = function(row, col, num) {
var puzzle = this.clone(); // clone puzzle
puzzle.grid[row*9 + col] = num; // mutate clone
return puzzle; // return clone
}
Speed Tests
The first version using new
is very fast using Node:
$ time node Sudoku.js
real 0m0.720s
user 0m0.699s
sys 0m0.016s
The second version using Object.create()
is consistently over 10x slower:
$ time node Sudoku2.js
real 0m7.746s
user 0m7.647s
sys 0m0.091s
A similar question here noted that Object.create()
is a lot slower in browsers, while I am also seeing a large disparity with node.js as well. I can certainly see timing discrepancies between JS engines, but a > 10x difference?!? Does anyone know why the difference is over an order of magnitude?!
You can find the source code here.
Update with Annotated Answer
Thanks to Bergi's answer below I changed the line in the clone
method from
var puzzle = Object.create(this);
to this:
var puzzle = Object.create(sudokuPuzzle);
which avoids long and complex inheritance chains (i.e., I always inherit from the same base object) and I now get speed results comparable to using new
. Thanks Bergi.