为什么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.create
和new
(与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)真的没有效果。