-1

We have the usual example code where everything works.

(myFunction gets triggered on an onclick event.)

"use strict";
console.clear();

const obj = {
    name: "falana",
    count: 0
};

function myFunction() {
    obj.count++;
    console.log(obj.count);
    console.log(obj.name);
    console.log(obj);
}

---Output---

1
"falana"
// [object Object] 
{
  "name": "falana",
  "count": 1
}

From this example, we can access a global object obj inside another function (in this case, myFunction) without any ReferenceError.

I was trying to create a single page Twitter clone (only DOM manipulation) and kept getting this error. Uncaught ReferenceError: Cannot access 'userData' before initialization at postMessage

---Javascript that's causing error---

window.onload = function() {
  console.clear();
}

const userData = {
  username: 'Chinmay Ghule',
  userhandle: generateUserhandle(this.username),
  userPostCount: 0
};

function generateUserhandle(userData) {
  const usernameArr = userData.username.split(" ");
  usernameArr.forEach(element => {
    element.toLowerCase();
  });

  return "@" + usernameArr.join("");
}

// posts message entered in #message-text to
// message-output-container.
function postMessage() {

  console.log(userData);

  // get message from #message-text.
  const message = document.getElementById('message-text').value;
  console.log(`message: ${message}`);

  // check for length.
  console.log(`message length: ${message.length}`);
  if (message.length === 0) {
    return;
  }

  // create new div.
  const card = document.createElement('div');
  const userInfo = document.createElement('div');
  const userMessage = document.createElement('div');

  const usernameSpan = document.createElement('span');
  const userhandleSpan = document.createElement('span');
  const beforeTimeDotSpan = document.createElement('span');
  const timeSpan = document.createElement('span');

  usernameSpan.classList.add('username');
  userhandleSpan.classList.add('userhandle');
  beforeTimeDotSpan.classList.add('before-time-dot');
  timeSpan.classList.add('time');

  userInfo.appendChild(usernameSpan);
  userInfo.appendChild(userhandleSpan);
  userInfo.appendChild(beforeTimeDotSpan);
  userInfo.appendChild(timeSpan);

  console.log(`userInfo : ${userInfo}`);

  userInfo.classList.add('user-info');
  userMessage.classList.add('output-message');

  card.appendChild(userInfo);
  card.appendChild(userMessage);

  console.log(`card : ${card}`);

  card.classList.add('output-message');

  userMessage.innerText = message;

  // check for number of posts.
  if (userData.userPostCount === 0) {
    let noMessageDiv = document.getElementById("no-message-display");

    noMessageDiv.remove();
  }

  // append new div.
  const messageOutputContainer = document.getElementById('message-output-container');

  messageOutputContainer.appendChild(card);

  // increment userPostCount.
  userData.userPostCount++;
}

Why am i getting this ReferenceError in this case, while it didn't in our first example code?

Chinmay Ghule
  • 91
  • 1
  • 6
  • 1
    Please put the non-working code into your question rather than relying on an external link – Robin Zigmond Nov 04 '21 at 19:46
  • 1
    So why are we not seeing the code that causes this error? – epascarello Nov 04 '21 at 19:46
  • 2
    The error message seems pretty clear to me: You are trying to access the variable before it was assigned a value. – Felix Kling Nov 04 '21 at 19:47
  • I've edited the question. – Chinmay Ghule Nov 04 '21 at 19:48
  • Your code makes no sense `userhandle: generateUserhandle(this.username),`<--pass string.... `const usernameArr = userData.username.split(" ");` <-- reference object – epascarello Nov 04 '21 at 19:50
  • there are quite a few things wrong here, I'm afraid. Just from a quick look: 1) `userData` the function argument shadows the global object of the same name, so you can't reference that object inside the function, 2) even if you could, you're calling it inside a property definition of that ssame object, so it wouldn't have a value yet anyway, 3) `this` will not be what you expect in the `this.username` you assign to the argument in the `userhandle` property – Robin Zigmond Nov 04 '21 at 19:51
  • Why do you split an array into a string to lowercase each letter one by one which does nothing because forEach does not return anything? – epascarello Nov 04 '21 at 19:51
  • 1
    https://stackoverflow.com/questions/4616202/self-references-in-object-literals-initializers – epascarello Nov 04 '21 at 19:54
  • @RobinZigmond I'm trying to reference userData properties inside the two functions generateUserhandle and postMessage. – Chinmay Ghule Nov 04 '21 at 19:54

1 Answers1

1

Your code had quite some issues...

The biggest change here was getting rid of generateUserhandle entirely and making it with a getter.

  get userhandle() {
    return this.username.toLowerCase()
  },

Working demo

window.onload = function() {
  console.clear();
}

const userData = {
  username: 'Chinmay Ghule',
  get userhandle() {
    return this.username.toLowerCase()
  },
  userPostCount: 0
};

// posts message entered in #message-text to
// message-output-container.
function postMessage() {
  console.log(userData);

  // get message from #message-text.
  const message = document.getElementById('message-text').value;
  console.log(`message: ${message}`);

  // check for length.
  console.log(`message length: ${message.length}`);
  if (message.length === 0) {
    return;
  }

  // create new div.
  const card = document.createElement('div');
  const userInfo = document.createElement('div');
  const userMessage = document.createElement('div');

  const usernameSpan = document.createElement('span');
  const userhandleSpan = document.createElement('span');
  const beforeTimeDotSpan = document.createElement('span');
  const timeSpan = document.createElement('span');

  usernameSpan.classList.add('username');
  userhandleSpan.classList.add('userhandle');
  beforeTimeDotSpan.classList.add('before-time-dot');
  timeSpan.classList.add('time');

  userInfo.appendChild(usernameSpan);
  userInfo.appendChild(userhandleSpan);
  userInfo.appendChild(beforeTimeDotSpan);
  userInfo.appendChild(timeSpan);

  console.log(`userInfo : ${userInfo}`);

  userInfo.classList.add('user-info');
  userMessage.classList.add('output-message');

  card.appendChild(userInfo);
  card.appendChild(userMessage);

  console.log(`card : ${card}`);

  card.classList.add('output-message');

  userMessage.innerText = message;

  // check for number of posts.
  if (userData.userPostCount === 0) {
    let noMessageDiv = document.getElementById("no-message-display");

    noMessageDiv.remove();
  }

  // append new div.
  const messageOutputContainer = document.getElementById('message-output-container');

  messageOutputContainer.appendChild(card);

  // increment userPostCount.
  userData.userPostCount++;
}
*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  margin: 0px;
  padding: 0px;
  font-family: Arial, Helvetica, sans-serif;
}

#container {
  /*background-color: lightskyblue;*/
  margin: 2.5rem 25%;
}

#user-info {
  /*background-color: orange;*/
  padding-bottom: 0.5rem;
}

.username {
  font-weight: bold;
}

.userhandle,
.before-time-dot,
.time {
  opacity: 0.75;
}

#message-text {
  width: 100%;
  margin-bottom: 0.5rem;
  font-size: 18px;
  padding: 0.5rem;
  resize: none;
  border-radius: 0.5rem;
  outline: 1px solid lightgray;
}

#message-button {
  float: right;
  padding: 0.375rem 1.5rem;
  font-weight: bold;
  font-size: 18px;
  border-radius: 1rem;
}

#message-button:hover {
  background-color: lightgray;
}

#message-input-container {
  background-color: lightskyblue;
  padding: 1rem;
  border-radius: 0.5rem;
}

#message-input-container::after {
  content: "";
  clear: both;
  display: table;
}

#message-output-container {
  /*background-color: lightskyblue;*/
  margin-top: 30px;
  border-top: 3px solid black;
}

#no-message-display {
  text-align: center;
  padding: 0.5rem;
}

.output-message {
  padding: 0.5rem;
  font-size: 18px;
  border-bottom: 1px solid lightgray;
}
<div id="container">
  <div id="message-input-container">
    <textarea id="message-text" rows="5" placeholder="Type your message here..." contenteditable="" value=""></textarea>
    <input id="message-button" type="button" value="Post" onclick="postMessage();" />
  </div>
  <div id="message-output-container">
    <div id="no-message-display">
      <span>No messages yet!</span>
    </div>
  </div>
</div>
Balastrong
  • 4,336
  • 2
  • 12
  • 31