I have the current code;
socket.on('KeyPress', function(data){
var ply = PLAYER_LIST[socket.id];
/* ... */
});
WebStorm is informing me that socket.id may not be initialized, and then when this event is triggered it does cause the error
TypeError: Cannot read property 'id' of undefined
The whole code is inside of
io.sockets.on('connection', function(socket){ /*...*/ });
Here is two of the on method I'm using;
In the first block you can see I'm doing the same thing yet it works..
Also on that note how secure is it to use socket.id to auth a user? Is it possible to force-set your own id?
You are a victim of a bad practice of defining variables with var within a loop and then getting bit by the influence of "variable hoisting" where a variable defined with var anywhere in the function is automatically declared at the start of the function and then initialized where your assignment was, meaning it's undefined everywhere in your function before that.
The problem is this line of code:
var socket = SOCKET_LIST[i];
That is redefining a local variable named socket that hides the one you actually want. Variables defined with var are function scoped. That means they are defined at the top of the function (this is called variable hoisting) and thus hides the other parent scoped socket variable.
Think of your function as starting like this:
socket.on('KeyPress', function(data) {
var socket; // this is hoisted from deeper inside the function
// and creates a new undefined socket variable
var ply = PLAYER_LIST[socket.id];
// other code here
});
This is essentially how Javascript sees your code. You can do a search on "Javascript variable hoisting" and see LOTS of articles written on the topic if you want more info.
The smallest change you can make it to change the name of this local variable to something else to it doesn't interfere with the parent scoped variable, but really this code structure is not ideal in the first place.
var localSocket = SOCKET_LIST[i];
var ply = PLAYER_LIST[p];
localSocket.emit(...)
In general it's a bad practice to define a variable with var inside a for loop. It leads to the "assumption" that it is scoped only to that loop, but in reality, it's scoped to the whole function and can mess with things outside of the loop.
In ES6, you can use let or const instead of var to declare a variable that is actually scoped to only the block of the loop.
Of other note, you should NEVER be iterating arrays with for/in. That iterates all array properties (including other enumerable object properties), not just array elements. ES6 adds for/of for iterating arrays this way. In ES5, you can use the more traditional for loop or .forEach().
Related
One of the key features of const in JavaScript is that the const variable cannot be redeclared.
However, in this code that is grabbed from this link:
signalServer.on('discover', (request) => {
const clientID = request.socket.id // clients are uniquely identified by socket.id
allIDs.add(clientID) // keep track of all connected peers
request.discover(Array.from(allIDs)) // respond with id and list of other peers
})
Every time a new client connects to the server via a socket, a new const clientID = request.socket.id is created.
So the clientID variable is created more that one time even though it is a const.
How is that possible?
A variable name can only exist once in a scope. (Redeclaring one with var doesn't cause an error, doing so with let and const does).
Each call to a function creates a new scope.
There's still only one instance of that variable in that scope.
It's only being declared once in each scope that you have it, if clientID was in the outer scope, let's say along with signalServer then it would work the way you think it did
this constant only exists in the block of the callback function. after the function is executed, the constant is unloaded from memory.
const are block scoped const - JavaScript | MDN.
In the snippet, every time the callback function is called after discover event is triggered, a new execution context is created for the callback function.
Scope for const clientID is limited within the nearest curly braces, where it can be assigned only once at the time of declaration.
as far as I know variables in functions are always temporary if they are declared in the function scope. So even though it's a const it's still temporary since it's declared inside a function. You however would not be able to declare a different variable with the same identifier. so saying const x and later on saying let x isn't possible. If you had identified the const x outside of the function scope you wouldn't be able to set a variable with the same identifier in the function scope.
Here is what I want:
var Validator = function () {
this.do = function () {
alert(INTANCENAME); /// SHOULD BE 'FOO'
}
}
var FOO = new Validator().do();
Is it possibe to implement in Javascript?
The truth is there is no point of doing that, the only way I can hardly think is to loop all window or scope objects and check some kind of equality with the current object, something like
this.do = function () {
for(var key in window) {
if(this === window[key]) {
alert(key);
}
}
};
In order to work call it after you assign it.
var FOO = new Validator();
FOO.do();
Another issue that can come up is that an instance (a reference) can be stored in various variables so maybe will not get what you expect.
The literal answer to your question would be:
Use (new Error()).stack to get information on the line and the function where the do() method was called.
Use JS parser (e.g. Esprima) to find out what variable it was called on (if any, the method itself might be assigned to a variable).
I do not recommend doing this though.
There's no way to directly do what you're asking for here. Objects themselves are not in any defined by their matching variable name - in fact it's possible to have objects that exist that are not directly assigned to a variable, and multiple variables assigned to the same object.
The javascript interpreter uses our variable names as identifiers to help with the code execution, but once it's running the variable name makes no difference to the running javascript program, as it's probably been reduced to a memory reference by the time it's executing, completely separated from the original code that you wrote.
Edit: Answer by yannis does kind of simulate this, but it relies on working with variables available in a specific scope - what I ment was that there's no direct way to do this from within the object itself as per your example in the question.
function exampleFunction(){
var theVariable = "Lol!";
var variable2 = Lol.toLowerCase();
console.log(theVariable);
delete theVariable; //to prevent bugs, I want to ensure that this variable is never used from this point onward.
console.log(theVariable); //This still prints "Lol!", even though I just tried to delete the variable.
}
In JavaScript, is it possible to prevent a variable from being used in a function after a certain point? I've tried declaring a string called theVariable, and then I tried to delete the variable using delete theVariable, but console.log(theVariable) still prints theVariable's value even after that point.
I tried using delete theVariable to make theVariable unusable from that point onward (in order to prevent myself from accidentally using the variable when it is no longer needed), but it doesn't appear to have that effect. Is there any way to work around this limitation?
One way is to limit its scope. Since JavaScript doesn't have block scope, that requires an IIFE (or similar technique):
function exampleFunction(){
var variable2;
(function() {
var theVariable = "Lol!";
variable2 = Lol.toLowerCase();
console.log(theVariable);
})();
// theVariable is now out of scope, and cannot be referenced
}
In that case you can set the value to undefined like theVariable = undefined
The delete function does not work as you expected
From docs
The delete operator removes a property from an object.
In this case theVariable is not a property of an object, it is a variable in the current function scope.
You cannot delete primitive types, only objects. If you don't want to use a variable after a certain point, just review your code so that you don't use it. Unfortunately, JS does not have block scoping to restrict the visibility of variables. You'll have to check for this manually.
Alternatively, set the value to undefined.
I'm new to JavaScript, and have a simple (I presume) question regarding best practices for accessing variables in functions:
When should I declare a global variable, as opposed to simple passing a value into a function?
Declaring a global variable should only be used as an option of last resort.
Global variables are bad in general and especially so in javascript. There is simply no way to prevent another piece of javascript from clobbering your global. The clobbering will happen silently and lead to runtime errors.
Take the following as an example.
// Your code
myParam = { prop: 42 };
function operateOnMyParam() {
console.log(myParam.prop);
}
Here i've declared 2 global variables
myParam
operateOnMyParam
This might work fine while testing your javascript in isolation. However what happens if after testing a user combines your javascript library with my javascript library that happens to have the following definitions
// My code
function myParam() {
console.log("...");
}
This also defines a global value named myParam which clashes with your myParam. Which one wins depends on the order in which the scripts were imported. But either way one of us is in trouble because one of our global objects is dead.
There are many, many reasons.. but an easy one is.. The argument of a function only exists in the function, while it's running. A global variable exists all the time, which means:
it takes up memory until you manually 'destroy' it
Every global variable name needs to be unique
If, within your function.. you call another function.. which ends up calling the first function, all of a sudden you may get unexpected results.
In short: because the function argument only lives for a really short time and does not exist outside the function, it's much easier to understand what's going on, and reduced the risk of bugs greatly.
When dealing with framework-less JavaScript I'll store my simple variables and functions in an object literal as to not clutter up the global namespace.
var myObject = {
variableA : "Foo",
variableB : "Bar",
functionA : function(){
//do something
//access local variables
this.variableA
}
}
//call functions and variables
myObject.variableA;
myObject.functionA();
I have this function that populates the currsong variable with data.
The problem is that the variable currsong is only available inside the function and I need to access it globally.
// get a single audio url
echonest.artist(artist).audio( function(audioCollection) {
var currsong = audioCollection.data.audio[0].url;
return currsong;
});
Thank you!
To declare a global variable, you can always remove var:
currsong = audioCollection.data.audio[0].url;
I'm not sure if a global variable is a good solution for whatever you're trying to do, though. People suggest to avoid them for reason.
edit
An example.
Note, the variable will be undefined before function is executed first time. In your code, you only pass it into audio, you don't actually invoke it.
edit2
As Tgr notes, you can also declare global variable explicitly: window.currsong = .... There's no functional difference, but it improves code quality.
Scope is an interesting bird in javascript. So is closure.
Observation 1: you are returning a value from an inline function; that return value is meaningless.
Observation 2: by using the "var" keyword, you are specifying a local scope. Removing var will make the variable global. However, even if you do that it is possible that you will attempt to access that variable before the function gets triggered (i.e. it will be undefined).
Since you're just starting to wrap your head around the concept of closure and javascript scope, I'd recommend reading up on it and then rethinking your application design (since I would be willing to bet that you will learn something which prompts another approach).
In the mean time, try defining the variable outside of the inline function and giving it a temporary value. After that remove "var" from inside of the function.
// get a single audio url
var currsong = "temporary value";
echonest.artist(artist).audio( function(audioCollection) {
currsong = audioCollection.data.audio[0].url;
return currsong;
});
I've rewritten your code to make it a little more clear for myself and others. Please let me know if I've transliterated something incorrectly.
Basically, it looks like you're trying to get curSong as follows:
echonest.artist(artist).audio(
function(audioCollection){
var curSong = audioCollection.data.audio[0].url;
return curSong;
}
);
Right now, what you're doing is passing a function (the anonymous function defined by function(audioCollection)) to the audio function of whatever artist(artist) returns. As such, the curSong value is returned to audio(), and then only when audio() actually runs the function that its handed. I would look at audio() and try to see if there is a way to get curSong out of it. Otherwise, I'd do as slifty describes above and declare curSong in a larger scope, so that it can be accessed even outside of audio().
EDIT: For example, a sample audio function could be as follows:
function audio(inputFunction){
var audioCollection = getAudioCollection();
var song = inputFunction(audioCollection);
return song;
}
The variable curSong is in an anonymous function being passed to audio(). As such, it doesn't exist until that anonymous function is executed, as in the above code. Now, when you run your code (from the first snippet), the anonymous inner function will return curSong to audio(), and audio() will return curSong to you.