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

时间:2016-03-23 16:26:17

标签: javascript node.js

我在JS中使用回溯编写了一个简单的数独求解器。努力做到纯粹的功能性"所有我的9x9谜题数组都是不可变的,因此每当插入新数字时都会创建一个新数组。

使用new SudokuPuzzle

的版本1

在第一个版本中,我使用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()

的版本2

我编写了另一个版本,我使用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。

2 个答案:

答案 0 :(得分:5)

您已经确定V8无法优化Object.createnew一样好(与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)实际上是无效的。