为什么Node的Object.create(foo)比新的Foo()慢得多?

我用JS中的回溯编写了一个简单的数独求解器。 为了成为“纯粹的function”,我所有的9×9拼图数组都是不可变的,因此每当插入一个新数字时都会创build一个新的数组。

版本1使用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 } 

版本2使用Object.create()

我写了另一个版本,我使用Object.create()来代替,并有一个基础对象sudokuPuzzle ,我inheritance创build新的难题。 这里是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 } 

速度testing

使用Node的第一个版本非常快:

 $ 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 

类似的问题在这里指出, Object.create()在浏览器中慢了很多,而我也看到了与node.js差别很大的情况。 我当然可以看到JS引擎之间的时间差异,但差异大于10倍! 有谁知道为什么差异超过一个数量级?!

你可以在这里find源代码 。

带注释的答案更新

感谢Bergi的回答,我改变了clone方法中的一行

  var puzzle = Object.create(this); 

对此:

  var puzzle = Object.create(sudokuPuzzle); 

这避免了冗长和复杂的inheritance链(即,我始终从同一个基础对象inheritance),现在我可以获得与使用new速度结果相媲美的速度结果。 谢谢Bergi。

您已经确定V8无法优化Object.createnew (与SpiderMonkey相比)。 或者至less在历史上做过。 有关详细信息,另见这篇博文 。

不过,还有第二个原因是速度较慢:你的两个代码有不同的结果。 你将不得不使用

 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 }; 

创build与使用new SudokuPuzzle()创build的克隆等效的克隆。

问题是,当您使用Object.create(this) ,您正在创build一个具有不同原型的新对象 – 即this实例。 经常从对方克隆,你正在创build一个非常复杂的inheritance层次结构。 而所有这些具有不同原型的对象都会有不同的隐藏类 – 这会阻止优化

你可以检查比较Object.create和new的其他post,对我来说这是直觉 – 如果你使用new关键字,那么引擎知道它想要创build什么。 如果您使用Object.create引擎需要做一些额外的工作来检查,重写types,…

就像在文章中写的那样,如果你只是创build一些对象,那么性能应该不重要(7s?真的?)。 然而,JS并不是真正为反思而build立的。 所以方法this.clone()Object.create(this)真的没有效果。