CODE DEMO:
See Line 34:
// Tree creation functions
function branch(b) {
var end = endPt(b), daR, newB;
...
(where endPt(b), daR, newB are variables defined in this function, but omitted for simplicity)
What is going on here?
Possible solution: I've read this assets var end equals each of these,
In JavaScript you can use commas to group any number of expressions
into a single statement. This is basically an artifact of the for
statement, where multiple assignment expressions are often grouped
together in the header.
from here:
Does that explanation directly apply here?
Pretty simple, you can declare multiple variables inline by separating via comma, so we can break down your example:
function branch(b) {
var end = endPt(b), //a new variable called "end" is created and assigned the result of endPt with "b" as the parameter
daR, //an empty variable called "daR" is declared
newB; //an empty variable called "newB" is declared
As #Phil points out, it's probably easier to separate this statement into:
var end = endPt(b);
var daR, newB;
(where endPt(b), daR, newB are variables defined in this function, but omitted for simplicity)
What is going on here?
You are seeing the declaration of the variables end, daR and newB. end also is initialized with the value endPt(b). It is a multiple var statement equivalent to
var end = endPt(b);
var daR;
var newB;
Does that explanation directly apply here?
No, that explanation does not apply here, it does not have anything to do with the construct you have here. You should rather read the other answers on that question.
The "comma expression" explanation would apply to
var end = (endPt(b), daR, newB);
where it would evaluated endPt(b), daR, and then assign the value of newB to end.
Related
I'm still learning so I might be wording this wronf (which might be why I haven't had any luck in finding an answer by searching thus far) or I might be doing this wrong all together.
Basically I'm trying to create a function that, when called, will create an object (which is made up of other objects). If I create this Characters object outside of the function, I can access it as I'd expect to but when done inside the function, I can't seem to access it. I'm testing this in the console built into Chrome.
Here's my code.
function q1(ans) { //Are you male or female?
"use strict";
//store all above objects into new object
if (ans === "male") {
var Characters = {
spike: spike,
jet: jet,
vicious: vicious
};
}
if (ans === "female") {
//store all above objects into new object
var Characters = {
faye: faye,
julia: julia,
ed: ed
};
}
return Characters;
}
(The objects spike, jet, vicious (etc) are defined elsewhere and can be accessed without any issue.)
If I call my function q1("male"); the console seems to log that the Characters object is created but if I then try to access it by just typing Characters I get an error (ReferenceError: Characters is not defined). If I were to create this Characters object outside of a function and then try to access it as mentioned above, this works fine. This leads me to believe I'm not returning it properly (or I'm doing something else wrong entirely). What am I missing here?
Thanks in advance for any assistance.
this is due to scope. this means that character is only live inside the function so you can't access it outside of the function. what you have to do is set a new variable equal to the return value of the function when u call it. That way you can reference the returned variable outside the function and use it later on.
var male = q1("male")
Since you have already defined characters outside the scope of q1 you will need to reassign the Characters variable by returning Characters from the method.
So reassign the Characters and it should fix the problem.
One more very bad way is to not use var Characters, instead use Characters = ..., but bear in mind using global variable is not at all recommended and is a very bad practice.
I have module that returns an object to a callback with the structure of the following pseudocode:
module.exports=function(){
global.foo=function(){
var callbacks=Array.prototype.slice.call(arguments,1);
var conf=arguments[0];
return global[callbacks.shift()].apply(null,[conf,callbacks]);
}
global.bar=function(){
var callbacks=Array.prototype.slice.call(arguments,1);
var conf=arguments[0];
return global[callbacks.shift()].apply(null,[conf,callbacks]);
}
// This one is where i ran into trouble
global.foobar=function(){
var callbacks=Array.prototype.slice.call(arguments,1);
var conf=arguments[0];
// right here
if(callbacks.length===[].length){
return global[callbacks.shift()].apply(null,[conf,callbacks]);
}
}
var conf={'pseudo':'object'};
return global['foo'](conf,'foo','bar','foobar');
}
Everything works fine until foobar, and what happens is that when I get down to checking if there are anymore callbacks - because if their are, I want to call them - callbacks.length is 1 at this point. This didn't make sense to me, and I discovered that at that point callbacks actually equaled [[]]. I don't know why this is getting returned, so I guess I have two questions. Can anyone see why callbacks is equal to [[]]?
What I discovered along the way is that when using Strings called as functions in the global namespace - as in var bar='foo'; global[bar]() calls global.foo() - multiple brackets are ignored. So for example, global[[[[[[['foo']]]]]]] === global['foo']. Also weirdly enough (at least to me), the following:
// With
global.bar='foo';
global.foo=function(){return true;}
//the following
global[global[bar]]()
// throws a TypeError: undefined is not a function
None of that makes sense to me.
I recognize that this question ends up asking three questions, and is a bit disorganized, but frankly I'm a bit confused, and I'm not really sure how I want to ask what I want to know, so I just said everything.
My main questions is regarding the multiple brackets, and why that works.
Thanks
My main questions is regarding the multiple brackets, and why that
works.
The multiple brackets works only because it's trying to do a string conversion to get a property name. So, no matter how many nested arrays you have, it ends up calling .toString() on each array and since the inner array only has a single item that has a string in it, multiple .toString() calls just end up resolving to the inner string.
Here's a demo of the same concept in a browser:
window.foo = "hi"
document.write(window[[[[["foo"]]]]]);
For some further explanation:
["foo"].toString() === "foo";
So, then:
[["foo"].toString()].toString() === "foo"
But, if the outer .toString() is there, it is already driving things to a string so you can remove the inner .toString() and thus you get:
[["foo"]].toString() === "foo"
And, you can then nest it as many levels as you want as long as something on the outer level is driving it to a string.
And, since property names are always strings, when you do:
global[[[[[[['foo']]]]]]]
You're ultimately asking for a property name that can be looked up on the global object and since the property name is a string, that calls .toString() on the outer array. When the outer array goes to convert it's only item to a string, it asks that one item to convert itself to a string so this:
global[[[[[[['foo']]]]]]]
turns into this:
global[[[[[[['foo'].toString()].toString()].toString()].toString()].toString()].toString()]
Which hopefully explains why you end up with nothing more than this in the end:
global["foo"]
FYI, if you look at the ES5/ES6 spec for Array.prototype.toString(), it ends up calling array.join() which for a single element array just ends up doing a .toString() on that single element which is how it causes all the nested arrays to just call .toString() on themselves. The outer array calls .toString() on the first nested array which called .toString() on it's single item which is the next nested array and so on until it finally gets to the inner string which is returned back from all the .toString() calls. And, it matters not how many arrays deep it is nested.
Spec reference for Array.prototype.toString(): http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.tostring
Spec reference for Array.prototype.join() which is called by Array.prototype.toString(): http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.join
In your other scenario here:
// With
global.bar='foo';
global.foo=function(){return true;}
//the following
global[global[bar]]()
// throws a TypeError: undefined is not a function
None of that makes sense to me.
Here's what is going on in global[global[bar]]() one piece at a time:
bar resolves to the string 'foo'.
So, global[bar] resolves to global['foo'] which is your function.
But, then you try to do another global reference on it like this global[global[bar]], then you are essentially trying to do:
global[yourfunction]
or
global[global.foo]
That will try to convert yourfunction to a string and look up that property on the global object. That will be undefined. So, you will then try to do undefined() which is a TypeError because undefined is not a function.
What will work in this case is just:
global[bar]()
I am trying to accomplish something like in : eval() with variables from an object in the scope
The correct answers suggests using the "with" keyword, but I can't find any examples of someone actually using "with". Can someone explain how to pass multiple variables using "with" into an "eval" expression like in the link above ?
i wouldn't recommend using with or eval except as a learning exercise because either one slows code down, and using them both at once is especially bad and frowned upon by the larger js community.
but it does work:
function evalWithVariables(code) {
var scopes=[].slice.call(arguments,1), // an array of all object passed as variables
A=[], // and array of formal parameter names for our temp function
block=scopes.map(function(a,i){ // loop through the passed scope objects
var k="_"+i; // make a formal parameter name with the current position
A[i]=k; // add the formal parameter to the array of formal params
return "with("+k+"){" // return a string that call with on the new formal parameter
}).join(""), // turn all the with statements into one block to sit in front of _code_
bonus=/\breturn/.test(code) ? "": "return "; // if no return, prepend one in
// make a new function with the formal parameter list, the bonus, the orig code, and some with closers
// then apply the dynamic function to the passed data and return the result
return Function(A, block+bonus+code+Array(scopes.length+1).join("}")).apply(this, scopes);
}
evalWithVariables("a+b", {a:7}, {b:5}); // 12
evalWithVariables("(a+b*c) +' :: '+ title ", {a:7}, {b:5}, {c:10}, document);
// == "57 :: javascript - How to pass multiple variables into an "eval" expression using "with"? - Stack Overflow"
edited to use any number of scope sources, watch out for property name conflicts.
again, i don't normally use with, but this was kinda fun...
To create an IDE that would autocomplete all variables the user declares but would be oblivious to other variables such as Math.PI or even the module Math, the IDE would need to be able to identify all identifiers relating to variables declared by the user. What mechanism could be used to capture all such variables, assuming you already have access to the AST (Abstract Symbol Table) for the program?
I am using reflect.js (https://github.com/zaach/reflect.js) to generate the AST.
I think it's pretty much impossible
Here is why I think it's pretty much impossible without executing it:
Let us go through the unexplored parts, from easy to hard.
Easy to catch:
Function scope is missed here:
(function(x){
//x is now an object with an a property equal to 3
// for the scope of that IIFE.
x;
})({a:3});
Here is some fun dirty tricks for you all.:
Introducing... drum roll... Block Scoping!!
with({x:3}){
x;//x is now declared in the scope of that with and is equal to 3.
}
try{ throw 5}catch(x){
x // x is now declared in the scope of the try block and is equal to 5;
}
(people reading: I beg you to please not use these last two for actual scoping in code :))
Not easy:
Bracket notation:
var n = "lo";
a["h"+"e"+"l"+n] = "world"; // need to understand that a.hello is a property.
// not a part of the ast!
The really hard parts:
Let us not forget invoking the compiler These would not show up in the AST:
eval("var x=5"); // declares x as 5, just a string literal and a function call
new Function("window.x = 5")();// or global in node
In node.js this can also be done with the vm module. In the browser using document.write or script tag injection.
What else? Of course they can obfuscate all they want:
new Function(["w","i","n","dow.x"," = ","5"].join(""))(); // Good luck finding this!
new Function('new Function(["w","i","n","dow.x"," = ","5"].join(""))()')();// Getting dizzy already?
So what can be done?
Execute the code, once, in a closed, timed environment when you update the symbol table (just the relevant parts)
See what's the generated symbol table is from the execution
Boom, you got yourself a symbol table.
This is not reliable but it's probably as close as you get.
The only other alternative I can think of, which is what most IDEs are doing is to simply ignore anything that is not:
object.property = ... //property definition
var a = ... //scoped
b = ... //global, or error in strict mode
function fn(){ //function declaration
object["property"] //property with a _fixed_ literal in bracket notation.
And also, function parameters.
I have seen no IDE that has been able to deal with anything but these. Since they're the most common by far, I think it's perfectly reasonable to count those.
By adding them onto am object that already exists....ie
window.mynewvar = 5;
function mynewfunc() {
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why would a JavaScript variable start with a dollar sign?
I realized some syntax with jquery and didnt know what it is. here goes:
var $foo = $("bar").blah();
var hello$ = $("stgelse").etc();
What is the difference between these? and why are they like that?
Also, For example:
var $foo = $("").blah();
var should already contain whatever right side is returning ? no?
Can you please elaborate?
In Javascript you can use $ in a variable name (or as a variable name all by itself, like it's used by the jQuery library for example), there is no special meaning in the language itself.
Some people use $ at the beginning of a variable name to indicate that the variable should contain a jQuery object, for example:
var $form = $('form');
A $ at the end of variable names was used in BASIC for string variables, which might be one reason for using it to mean something when naming variables in other languages also. Example:
10 LET NAME$="JOHN DOE"
20 PRINT NAME$
var $foo = $("bar").blah();
var is a keyword that makes the variable local in certain cases. See this question
$foo is the name of this variable. There is no need for the $, and indeed it confuses everything, but some languages (like PHP) need them to say "this is a variable". It could've been just foo
= is the assignment to make $foo have whatever comes from the right hand side
$ is another variable, but a special one: this is your JQuery thingy! From there you see it does all the JQuery stuff, like "find bar, do blah() etc.
The same basically goes for the other line, but in this case someone thought that hello$ would be a nice name for a var :)
here
var hello$ and $foo
hello$ , $foo are just a variable name
and $("").blah();
$ is jquery object
$ is just a name - names in JavaScript can contain dollar signs, and can consist of just a dollar sign.
Its like just normal javascript variable but as per convention is used to identify jquery objects variable from normal javascript variable. there nothing special about it.