Javascript - 尝试通过递归调用进行引用传递

Javascript - trying to do reference passing with recursive calls

在 2 人游戏的上下文中,我有一个执行递归调用的 C 函数,对于每次调用,它从全局数组变量和当前局部数组执行 memcpy。这是这个 C 函数(“game”数组在函数外声明为全局变量):

int game[8][8];

int recursive_function(int player, int *mx, int *my, int depth)                           

{                                                                                        
  int x, y;
  int eval, e;                                                                           
  int mx2, my2;                                                                          
  int game2[8][8];

  // TERMINAL CASE
  if (depth == 0) {
    return 1;
  }

  memcpy(game2, game, sizeof(game));                                                     
  eval = -INFINITY;                                                                        

  for (x = 0; x < 8; x++)       
    for (y = 0; y < 8; y++) {
      if (isplayabe((x, y, player)) {                                                    
        e = -recursive_function(OTHER(player), &mx2, &my2, depth-1);                          
      }
      if (e > eval) {                                                                    
        *mx = x; *my = y;
        eval = e;
      }                                                                                  
      memcpy(game, game2, sizeof(game));                                                 
      }                                                                                  
  return eval;
}

现在,我想在javascript中实现相同的功能。

我想我必须使用对象来传递引用。所以我创建了对象 HitHitTemp,每个对象都将数组的坐标作为属性:

  1. Hit.coordPlaybles(x,y) 坐标并使 link 等同于
  2. 上方的 game 变量
  3. HitTemp.coordPlaybles(x,y) 坐标并使 link 等同于
  4. 上方的 game2 变量

据此,我尝试使用由 :

定义的对象 Hit
// Player white and black
var playerWhite = ['white', 'black'];
var playerBlack = ['black', 'white'];

var Hit = {
 currentPlayer: playerBlack,
 coordPlayable: ['0', '0'],
 coordCurrent: ['0', '0'],
};

对象Hit在recursive_function(全局变量)外声明,而HitTemp只在这个函数(局部变量)中定义。

这是我所做的:

// Object Hit passed by reference
function recursive_function(Hit, depth) {
  // Evaluation
  var eval, e;

   // TERMINAL CASE
      if (depth == 0) {
        return 1;
      }

  // Local Hit object : EQUIVALENT OF "memcpy" ??
  var HitTemp = Object.assign({}, Hit);

  eval = -infinity;       

  for (var x = 0; x < 8; x++)
    for (var y = 0; y < 8; y++) {
      if (isplayabe((x, y, HitTemp)) { 
        // CALL RECURSIVE WITH OPPOSITE PLAYER (SWITCHING PLAYER)                                                   
        e = -recursive_function(OTHER(HitTemp.currentPlayer), depth-1);  
        if (e > eval) {
                  // HitTemp.coordCurrent[0] = *mx
                  // HitTemp.coordPlayable[0] = x
                  // HitTemp.coordCurrent[1] = *my
                  // HitTemp.coordPlayable[1] = y
                  HitTemp.coordCurrent[0] = HitTemp.coordPlayable[0];
                  HitTemp.coordCurrent[1] = HitTemp.coordPlayable[1];
                  eval = e;
                }
   // Final copy from HitTemp to Hitobject : Here also, equivalent to 
   // the final memcpy of C version ??
   Hit = Object.assign({}, HitTemp);
  }
return eval;
}

不幸的是,两个版本的结果完全不同(我确信 C 版本工作正常)。

谁能告诉我 Javascript“assign”方法是否是重现 C“memcpy”函数行为的正确方法?

如果没有,你能给我一些线索来用递归调用修复它吗?

更新 1:

感谢您的帮助。但是,我对建议的解决方案有疑问 @西尔塔。的确,如果我用 JSON.parse(JSON.stringify(HitCurrent)) 作为 :

进行深度复制
// Global variables : Player white and black
var playerWhite = ['white', 'black'];
var playerBlack = ['black', 'white'];

//Global variable Hit 
var Hit = {
 currentPlayer: playerBlack,
 coordPlayable: ['0', '0'],
 coordCurrent: ['0', '0'],
};

function recursive_function(HitCurrent, depth) {

// Deep copy
var HitTemp = JSON.parse(JSON.stringify(HitCurrent));

// Switch color for player

// BEFORE
console.log('BEFORE = ', HitTemp.currentPlayer);

// Switch
HitTemp.currentPlayer = (HitTemp.currentPlayer == playerBlack) ? playerWhite : playerBlack;

// AFTER : expected the opposite of BEFORE
console.log('AFTER = ', HitTemp.currentPlayer);

...
}

我得到 BEFOREAFTER :

BEFORE =  
Array [ "black", "white" ]

AFTER =  
Array [ "black", "white" ]

可以看到,"HitTemp.currentPlayer"的值是未切换,好像是“HitTemp.currentPlayer == playerBlack”设置为 false 而“HitTemp.currentPlayer”的“BEFORE”值设置为“playerBlack”。

我必须注意 recursive_function 是在 main() 中使用全局对象 Hit 调用的,例如:

    //Global variable Hit 
    var Hit = {
     currentPlayer: playerBlack,
     coordPlayable: ['0', '0'],
     coordCurrent: ['0', '0'],
    };

    // Main function
    function main() {

        recursive_function(Hit, maxDepth);
    ...

    }

这个问题与 HitCurrentHitTemp 对象的 深度复制 有关系吗?

更新 2:

如果我像这样只使用一个“=”(而不是两个“==”):

console.log('BEFORE = ', HitTemp.currentPlayer);
HitTemp.currentPlayer = (HitTemp.currentPlayer = playerBlack) ? playerWhite : playerBlack;
console.log('AFTER = ', HitTemp.currentPlayer);

然后切换工作:用三元运算符的条件来测试相等性的正确语法(一个或两个“=”符号)是什么?

Object.assign 执行浅拷贝。根据您上面的评论,您似乎想要一份深层副本。如果你知道这个数据结构不会改变,那么像这样的东西会起作用:

var HitTemp = Object.assign({}, Hit, {
    coordPlayable: Hit.coordPlayable.slice(0),
    coordCurrent: Hit.coordCurrent.slice(0)
});

如果您想要一个更简洁、更通用的解决方案,请查看 cloneDeep from lodash. Since this is a game and performance may be a concern this question 值得一试。

MDN Object.assign() https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Warning for Deep Clone

For deep cloning, we need to use other alternatives because Object.assign() copies property values. If the source value is a reference to an object, it only copies that reference value.

在你的情况下,currentPlayer: playerBlack 没有被深度复制。

解决方案如:

obj = JSON.parse(JSON.stringify(o));

这里被告知:What is the most efficient way to deep clone an object in JavaScript?

关于 更新 1:您比较两个不同的对象,它们是具有相同值的副本,但内存中的对象不同。尝试只比较字符串或整数以区分您的玩家。 – Siltaar 2 分钟前编辑

Regardine 更新 2 : 只有一个等号“=”的语法是一种归属声明。归因通常 return 正确。您正在尝试进行比较,所以我建议坚持使用“==”或“===”(如果对象类型很重要)。