Tic-Tac-Toe code in JavaScript I have developed a tic-tac-toe game in native JavaScript.
Can you tell me how to optimize more and what are the missing things? JSBIN

The logic, modular approach, testable and scalable?

(function() {
  var playerOneData = {
    name: null,
    arr: []
  };
  var playerTwoData = {
    name: null,
    arr: []
  };
  winnerFound = false;
  var clickCount = 2;

  var start = document.getElementById('start');
  var resultsList = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];
  var setApplicationView = function(screenId, display) {
    //     hide user infor form
    document.getElementById(screenId).style.display = display;
  };
  start.addEventListener('click', function() {
    //     fetch username
    playerOneData.name = document.getElementById('player-one-name').value;
    playerTwoData.name = document.getElementById('player-two-name').value;
    //     hide user info form
    setApplicationView('user', 'none');
    //     show game board
    setApplicationView('game-board', 'block');
    //     set the player's name
    document.querySelector('#p1-info span').innerHTML = playerOneData.name;
    document.querySelector('#p2-info span').innerHTML = playerTwoData.name;
  });

  var ifClicked = function(index, tile) {
    var i = 0;
    while (i &lt; tile.length) {
      if (index == tile[i])
        return false;
      i++;
    }
    return true
  };
  var selectedTiles = [];

  var winnerFinder = function(playersData, resultsList) {
    if(playersData.arr.length&lt;2) return true;
    var player = playersData.arr;
    var i = 0;
    resultsList.forEach(function(element) {
      i = 0;
      player.forEach(function(ele) {
        if (element.indexOf(ele) &gt;= 0) {
          i++;
        }
      });
      if (i == element.length) {
        matrix.removeEventListener('click', startMatrix);
        document.getElementById('result').innerHTML = "Winner is " + playersData.name;
        winnerFound = true;
        return false;
      }
    });
  };
  var matrix = document.getElementById('matrix');
  var startMatrix = function($event) {
    var target = $event.target;
    var tileIndex = +target.getAttribute('tile-index');
    var alreadyClickedStatus = ifClicked(tileIndex, selectedTiles);
    if (target.className === 'tile' &amp;&amp; alreadyClickedStatus === true) {
      selectedTiles.push(tileIndex);


      if (clickCount % 2 === 0) {
        playerOneData.arr.push(tileIndex);
        target.className = 'tile red';

        if (winnerFinder(playerOneData, resultsList) === false) {
          matrix.removeEventListener('click', startMatrix);
        }
      } else {
        playerTwoData.arr.push(tileIndex);
        target.className = 'tile blue';
        if (winnerFinder(playerTwoData, resultsList) === false) {
          matrix.removeEventListener('click', startMatrix);
        }
      }

      clickCount++;
      if (clickCount === 11 &amp;&amp; winnerFound === false) {
        document.getElementById('result').innerHTML = 'Match drawn';
      }
    }
  }
  matrix.addEventListener('click', startMatrix);
  var resetBoard = function() {
    winnerFound = false;
    clickCount = 2;
    matrix.addEventListener('click', startMatrix);
    document.getElementById('result').innerHTML = '';
    selectedTiles = [];
    var tile = document.querySelectorAll('.tile')
    tile.forEach(function(ele, index) {
      tile[index].className = 'tile';
    });
    playerOneData.arr = [];
    playerTwoData.arr = [];
  };
  var restart = document.getElementById('restart');
  restart.addEventListener('click', function() {

    resetBoard();
  });
  var newGame = document.getElementById('new-game');
  newGame.addEventListener('click', function() {
    //     show user info form
    setApplicationView('user', 'block');
    //     hide game board
    setApplicationView('game-board', 'none');
    resetBoard();
  });
})();
Note, some of these require a build process


the iife should be added in the build process, it's distracting
The code doesn't expose anything. It's untestable. 
var should be let or const
You can use arrow functions to turn some of the functions into one liners
Inconsistent formatting - I recommend getting a linter
setApplicationView - Should probably be replaced with show/hide functions. The current name is not very descriptive to me.
//     hide game board - You can make this a function and get rid of the comment. Several other similar issues.
ifClicked - A function name should generally describe what the functions does, not what happened when it was called. You could also just inline it.
winnerFinder - It would be so much nicer if this was called findWinner, and returned the result instead of storing it globally. Then you could test it as well.
As it stands, it actually returns false when winnerFound is true. Even more confusing.
winnerFinder - You can use player.filter here to get rid of the index variable
playerData.arr - What is arr?
var player = playersData.arr; - How can a player be an array?
document.getElementById - You can run all these calls at the top to shorten the code and get rid of unnecessary dom queries.
innerHTML - It's quite hard to tell how this whole thing works with view logic and game logic all mixed in together.
In general I would recommend separating the view logic from the game logic as much as possible, and even better would be to make the view logic declarative.