简体   繁体   English

如何将参数值从一个模块传递到另一个模块?

[英]How to pass argument value from one module to another?

I'm trying to implement a functionality to a game of Tic Tac Toe.我正在尝试为 Tic Tac Toe 游戏实现功能。

  1. const "startModule" - Player should be able to select X or O on the start screen. const "startModule" - 玩家应该能够在开始屏幕上输入 select X 或 O。

  2. Then the value should be assigned to an argument "playerChoice" , which I'm trying to pass to "gameModule".然后该值应分配给参数“playerChoice” ,我正试图将其传递给“gameModule”。

  3. In "gameModule" , the "playerChoice" argument is being assigned to "circleTurn".“gameModule”中,“playerChoice”参数被分配给“circleTurn”。

  4. Based on the "circleTurn value, script should assign css value ("X_CLASS" or "CIRCLE_CLASS") to the "currentClass" argument in the "handleClick" function. This is where things are not working.基于“circleTurn 值,脚本应将 css 值(“X_CLASS”或“CIRCLE_CLASS”)分配给“handleClick”function 中的“currentClass”参数。这是不起作用的地方。

I'm still learning and would appreciate any help or pointers:)我还在学习,希望得到任何帮助或指点:)

edit: I've cut a lot from previous js section and left only substantial info (I hope)编辑:我从之前的 js 部分删减了很多,只留下了大量信息(我希望如此)

const startModule = (() => {
  
  let xButton = document.getElementById("player-choiceX")
  let oButton = document.getElementById("player-choiceO")
  let playerChoice;
  
  const xoChoice = () => {
    
    xButton.addEventListener('click', function(e){
      playerChoice = false;
      document.getElementById("playerChoice").style.display = "none";
      console.log(playerChoice);
    })
  }
  
  return {
    xoChoice, playerChoice
  };
  
})();


const gameModule = (() => {

    const board = document.getElementById("board");
    const X_CLASS = 'x';
    const CIRCLE_CLASS = 'circle';
    const resetButton = document.getElementById("reset");
    const winningMessageElement = document.getElementById("winningMessage");
    const cellElements = document.querySelectorAll("[data-cell]");
    const winningMessageTextElement = document.querySelector("[data-winning-message-text]");
    let circleTurn = playerChoice
  
    const WINNING_COMBINATIONS = [
        [0, 1, 2],
        [3, 4, 5],
        [6, 7, 8],
        [0, 3, 6],
        [1, 4, 7],
        [2, 5, 8],
        [0, 4, 8],
        [2, 4, 6],
      ]
      
    const startGame = () => {
      
        resetButton.addEventListener('click', startGame);
        cellElements.forEach(cell => {
          cell.classList.remove(X_CLASS)
          cell.classList.remove(CIRCLE_CLASS)
          cell.removeEventListener('click', handleClick)
          cell.addEventListener('click', handleClick, {once: true})
        })
        setBoardHoverClass()
        winningMessageElement.classList.remove('show')
    }  
      
    const handleClick = (e) => {
        const cell = e.target
        const currentClass = circleTurn ? CIRCLE_CLASS : X_CLASS
        placeMark(cell, currentClass) 
        if (checkWin(currentClass)){
          endGame()
        } else if(isDraw()) {
          endGame(true)
        } else {
          swapTurns();
          setBoardHoverClass();
        }
    }
     
    }
    return {
        startGame, handleClick
    }
  
  })();
  
  startModule.xoChoice()
  gameModule.startGame()
  
  
  
  
  
  
  
  
  
  
  
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" type="text/css" href="styles.css">
    <script src="index2.js" defer></script>
    <title>TicTacToe</title>
</head>
<body>

    <div class="player-choice" id="playerChoice">
        <div class="xOrCircle">
                <div class="player-choiceX" id="player-choiceX"></div>
                <div class="player-choiceO" id="player-choiceO"></div>
        </div>
    </div>


    </div>
    <div class="board" id="board">

        <div class="cell" data-cell></div>
        <div class="cell" data-cell></div>
        <div class="cell" data-cell></div>
        <div class="cell" data-cell></div>
        <div class="cell" data-cell></div>
        <div class="cell" data-cell></div>
        <div class="cell" data-cell></div>
        <div class="cell" data-cell></div>
        <div class="cell" data-cell></div>
        
    </div>
    <div class="winning-message" id="winningMessage">
        <div data-winning-message-text></div>
        <button id="reset">Reset</button>
    </div>



</body>
</html>

So there are a few things about what you have that I want to point out.所以我想指出一些关于你所拥有的东西。

For the sake of explaining things, I am going to rewrite your startModule to make it easier to digest为了便于解释,我将重写您的startModule以使其更易于理解

const startModule = (() => {

  let playerChoice;

  const xoChoice = () => {
      playerChoice = false;
  };

  return {
    xoChoice, playerChoice
  };
})();

Based on this version of startModule , checkout the outputs from the following code:基于此版本的startModule ,检查以下代码的输出:

startModule.playerChoice; // undefined
startModule.xoChoice();
startModule.playerChoice; // undefined

Ok so what went wrong that playerChoice did not become false?好的,那playerChoice没有变成 false 出了什么问题? It has to do with something called pass-by-value and pass-by-reference (more on that here )它与称为按值传递和按引用传递的东西有关(更多信息请参见 此处

Basically, because playerChoice was assigned a primitive value ( undefined ), when it was returned here:基本上,因为playerChoice被分配了一个原始值( undefined ),当它在这里返回时:

return {
  xoChoice, playerChoice
};

The return statement only returned the primitive value undefined , not a reference to say an Object. return 语句只返回原始值undefined ,而不是 Object 的引用。

Fortunately, there is a work around, by utilizing the pass-by-reference functionality in Javascript.幸运的是,有一个解决方法,即利用 Javascript 中的传递引用功能。

If instead of storing playerChoice with a primitive value ( undefined ) and returning it, we could store an Object with the necessary context of the module.如果不是用原始值 ( undefined ) 存储playerChoice并返回它,我们可以用模块的必要上下文存储一个 Object。 This should work because Objects are passed-by-reference, not passed-by-value.这应该有效,因为对象是按引用传递的,而不是按值传递的。 The code for this can look something like this:这个代码看起来像这样:

const startModule = (() => {

  let context = {
    playerChoice: undefined    
  }; // This is a JSON Object!

  const xoChoice = () => {
    context.playerChoice = false;
  };

  return {
    xoChoice, context
  };
})();

Now let's look at what is outputted from the following code based on this version of startModule:现在让我们看一下基于此版本的 startModule 从以下代码输出的内容:

startModule.context.playerChoice; // undefined
startModule.xoChoice();
startModule.context.playerChoice; // false

It works!有用! This is the case because since we are returning an Object ( context ), so we are returning a reference to a place of storage (to my knowledge:) ), instead of returning a primitive value (ex. undefined , false ) with no reference to a place in storage.之所以如此,是因为我们返回的是 Object ( context ),所以我们返回的是对存储位置的引用(据我所知:)),而不是返回没有引用的原始值(例如undefinedfalse )到存储的地方。 All of this means that the playerChoice that is changed when the xoChoice function is called is interlinked with the playerChoice that is returned when startModule is first called.所有这些意味着调用playerChoice function 时更改的xoChoice与首次调用startModule playerChoice相互关联的。

Ok so how can you utilize this information to share the value of playerChoice amongst the modules?好的,那么您如何利用此信息在模块之间共享playerChoice的值? For the sake of answering this question, I am going to again, simplify gameModule to make things easier to digest.为了回答这个问题,我将再次简化gameModule以使事情更容易理解。

const startModule = (() => {
  // ... (What we previously had)
})();
const gameModule = (() => {
  let circleTurn = context.playerChoice;

  return {
    circleTurn
  };
})();

Same as before, let's run some code to see what's happening:和以前一样,让我们运行一些代码看看发生了什么:

startModule.context.playerChoice; // undefined
gameModule.circleTurn; // undefined

startModule.xoChoice();
startModule.context.playerChoice; // false
startModule.circleTurn; // false

So there you go, using pass-by-reference we we're able to transmit data from one module ( startModule ), to another ( gameModule )!所以你是 go,使用传递引用我们能够将数据从一个模块 ( startModule ) 传输到另一个 ( gameModule )!

Feel free to ask any other questions, and if you'd like I can show you another interesting alternative way to coding this.欢迎提出任何其他问题,如果您愿意,我可以向您展示另一种有趣的替代编码方式。

EDIT: Here is the interesting (not better or worse) alternative way.编辑:这是有趣的(不是更好或更坏)替代方式。 With the previous way, you ran a function that did all this stuff to return an informative JSON Object to which you can retrieve information like a normal JSON Object. Instead of making startModule the return value of a function, you can simply assign startModule to a JSON Object, with functions that do stuff (the stuff from earlier) as value of the Object. It can look something like this:使用以前的方法,您运行了一个 function,它完成了所有这些工作,返回了一个信息丰富的 JSON Object,您可以向其中检索信息,例如正常的 JSON Object。与其让 startModule 成为startModule的返回值,不如将 startModule 简单地分配给startModule ,您可以JSON Object,具有做东西的功能(之前的东西)作为 Object 的值。它看起来像这样:

const startModule = {
  playerChoice: undefined,
  xoChoice: function () {
    // 'this' references the 'startModule' Object
    this.playerChoice = false;
  }
}

As you notice, startModule is now a JSON Object, but still with all the same components as before.如您所见, startModule现在是 JSON Object,但仍具有与以前相同的所有组件。 It's important to read up about the this keyword, as it involves itself heavily with this alternative.阅读有关this关键字的信息很重要,因为它与 this alternative 密切相关。 (FYI, if you're using arrow functions, this keyword is never assigned, so make sure you use ES5 functions if you want to use this ). (仅供参考,如果您使用箭头函数,则永远不会分配this关键字,因此如果您想使用this ,请确保使用 ES5 函数)。

Let's look at the following code and its output:让我们看看下面的代码及其 output:

startModule.playerChoice; // undefined;
startModule.xoChoice();
startModule.playerChoice; // false

And everything seems to be working fine.一切似乎都运行良好。 While playerChoice was initially undefined , calling xoChoice successfully mutated the value to false .虽然playerChoice最初是undefined的,但调用xoChoice成功地将值变为false

Now there is a small issue with this alternative.现在这个替代方案有一个小问题。 Say when you create the startModule you want to automatically do some logic (Maybe you want to make an HTTPS request to check the user's Tic Tac Toe win streak, maybe you wanna check if the user is logged in, etc).比如说当你创建startModule时你想要自动执行一些逻辑(也许你想发出 HTTPS 请求来检查用户的 Tic Tac Toe 连胜记录,也许你想检查用户是否登录,等等)。 To do this, it's common practice to assign init to startModule , and assign the value to a function that perform initial logic.为此,通常的做法是将init分配给startModule ,并将该值分配给执行初始逻辑的 function。 It can look something like this:它看起来像这样:

const startModule = {
  playerChoice: undefined,
  xoChoice: function () {
    // 'this' references the 'startModule' Object
    this.playerChoice = false;
  },
  init: function () {
    // do initialization stuff
    this.userLoggedIn = true;
  }
}

Now obviously, we would need to run startModule.init() as soon as we assign startModule .现在显然,我们需要在分配startModule后立即运行startModule.init() Here's a more elegant solution to that:这是一个更优雅的解决方案:

const startModule = {
  playerChoice: undefined,
  xoChoice: function () {
    // 'this' references the 'startModule' Object
    this.playerChoice = false;
  },
  init: function () {
    // do initialization stuff
    this.userLoggedIn = true;

    return this;
  }
}.init();

Here, we call init as soon as we create the Object, but because init returns this , we can still assign startModule to this function call.在这里,我们一创建 Object 就调用init ,但是因为init返回this ,我们仍然可以将startModule分配给这个 function 调用。

Now let's look at a possible implementation of gameModule :现在让我们看看gameModule的可能实现:

const gameModule = {
  board: document.getElementById("board"),
  X_CLASS: 'x',
  CIRCLE_CLASS: 'circle',
  resetButton: document.getElementById("reset"),
  winningMessageElement: document.getElementById("winningMessage"),
  cellElements: document.querySelectorAll("[data-cell]"),
  winnningMessageTextElement: document.querySelector("[data-winning-message-text]"),
  circleTurn: startModule.playerChoice, // look for the playerChoice value in the startModule Object
  WINNING_COMBINATIONS: [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ],
  startGame: function () {
    // 'this' references the Object this function lives under
    this.resetButton.addEventListener('click', this.startGame);
    this.cellElements.forEach(cell => {
      cell.classList.remove(this.X_CLASS)
      cell.classList.remove(this.CIRCLE_CLASS)
      cell.removeEventListener('click', this.handleClick)
      cell.addEventListener('click', this.handleClick, {once: true})
    })
    setBoardHoverClass() // idk where this func comes from
    this.winningMessageElement.classList.remove('show')
  },
  handleClick: function (e) {
    // etc...
  }
}

With this implementation, all our variables are stored as key-value pairs, and we use this to reference the Object they're in and retrieve their values.通过此实现,我们所有的变量都存储为键值对,我们使用this来引用它们所在的 Object 并检索它们的值。 You can also see in the value to circleTurn that we use startModule.playerChoice to get the playerChoice value from startModule .您还可以在circleTurn的值中看到我们使用startModule.playerChoicestartModule获取playerChoice值。

I wish I knew the technical name for both these different implementations, but personally I enjoy the alternative I just showed, as it feels simpler to extend upon, and IMO, feels easier to separate logic in a clearer sense.我希望我知道这两种不同实现的技术名称,但就我个人而言,我喜欢我刚刚展示的替代方案,因为它感觉更容易扩展,而且 IMO 感觉更容易在更清晰的意义上分离逻辑。 N.netheless, you do you, both options are perfectly fine and offer their own pros and cons. N.netheless,你做你,这两种选择都非常好,并提供自己的优点和缺点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将参数从函数传递给另一个函数 - How to pass an argument from a function to another one nodejs将值从一个模块传递到另一个模块 - nodejs pass value from one module to another module 如何将值从一个 function 传递到另一个 - How to pass a value from one function to another 当一个文件中的值用作另一个文件的参数时,如何将多个JSON文件传递给Onservable数组? - How to pass multiple JSON file to Onservable Arrays when value in one file is used as argument for another file? 如何传递一个复选框值数组从一个JSP页面到另一个JSP页面 - How to pass an array of checkbox value From one JSP page to another 如何在JavaScript中将值从一个html页面传递到另一个页面? - How to pass value from one html page to another in JavaScript? 如何将值从一个 Jasmine JavaScript 测试传递到另一个测试 - How to pass a value from one Jasmine JavaScript test to another test 如何在 React 中将动态更新的值从一个组件传递到另一个组件? - How to pass dynamically updated value from one component to another in React? 如何在react js中将值从一个组件传递到另一个组件 - how to pass value from one component to another in react js JavaScript:如何将对象值从一个函数传递给另一个函数 - JavaScript: how to pass object value from one function to another
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM