我在JS中使用回溯编写了一个简单的数独求解器。努力做到纯粹的功能性"所有我的9x9谜题数组都是不可变的,因此每当插入新数字时都会创建一个新数组。
new SudokuPuzzle
在第一个版本中,我使用new Puzzle(puzzle)
方法克隆对象:
function SudokuPuzzle(obj) {
if (obj instanceof SudokuPuzzle) {
this.grid = obj.grid.slice(0); // copy array
} // ...
}
然后每当我更新数组时,我都会执行以下操作:
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
}
Object.create()
我编写了另一个版本,我使用Object.create()
代替了一个基础对象sudokuPuzzle
,我继承了它来创建新的谜题。这是clone()
方法:
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
}
本案例中的更新方法是
sudokuPuzzle.update = function(row, col, num) {
var puzzle = this.clone(); // clone puzzle
puzzle.grid[row*9 + col] = num; // mutate clone
return puzzle; // return clone
}
使用节点的第一个版本使用new
非常快:
$ time node Sudoku.js
real 0m0.720s
user 0m0.699s
sys 0m0.016s
使用Object.create()
的第二个版本的速度始终慢了10倍:
$ time node Sudoku2.js
real 0m7.746s
user 0m7.647s
sys 0m0.091s
similar question here注意到Object.create()
在浏览器中慢得多,而我也看到node.js的差异很大。我当然可以看到JS引擎之间的时序差异,但是> 10倍的差异?!?有谁知道为什么差异超过数量级?!
您可以在此处找到source code。
感谢Bergi的回答,我改变了clone
方法中的一行
var puzzle = Object.create(this);
到此:
var puzzle = Object.create(sudokuPuzzle);
避免了长而复杂的继承链(即,我总是从相同的基础对象继承),现在我得到的速度结果与使用new
相当。谢谢Bergi。
答案 0 :(得分:5)
您已经确定V8无法优化Object.create
和new
一样好(与SpiderMonkey相比)。或至少在历史上做过。另请参阅this blog post for details。
然而,第二个原因是速度慢得多:你的两个代码有不同的结果。你必须使用
SudokuPuzzle.prototype.clone = function() {
var puzzle = Object.create(SudokuPuzzle.prototype); // a new instance, without `new`
puzzle.grid = this.grid.slice(0); // copy array (usually initialised in constructor)
return puzzle; // return newly minted puzzle
};
创建与使用new SudokuPuzzle()
创建的克隆相同的克隆。
问题在于,当您使用Object.create(this)
时,您正在创建一个具有不同原型的新对象 - 即this
实例。经常互相克隆,您正在创建一个非常复杂的继承层次结构。所有这些具有不同原型的对象将具有不同的隐藏类 - prevents optimisations。
答案 1 :(得分:0)
您可以查看其他帖子comparing Object.create and new,对我来说这是直觉 - 如果您使用 new 关键字,则引擎会知道它想要创建的内容。如果您使用 Object.create ,引擎需要做一些额外的工作来检查,覆盖类型,......
正如在帖子中写的那样,如果你只创建了一些对象,那么表现应该不重要(7s?真的吗?)。但是 - JS并不是真正用于反思的。所以方法 this.clone()或 Object.create(this)实际上是无效的。