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...
Related
I'm trying to read through some source code on the internet, and I'm getting confused because the author defined a function as:
var _0x80a1 = function (x, a) {...}
But then only calls it using statements like this:
_0x80a1("0x0")
How does that work?
JavaScript parameters are optional you don't need to pass them. So you can do something like this:
function multiply(a, b) {
if(typeof b === 'undefined') {
b = 10;
}
return a * b;
}
console.log(multiply(5));
// expected output: 50
In newer versions of JS you can also do default parameters like this:
function multiply(a, b = 10) {
return a * b;
}
console.log(multiply(5));
// expected output: 50
No function "requires" an argument in JavaScript. It's not a strongly typed language.
I might be typing out of my own butt, but I think function's arguments are syntactic sugar in JS. You can always pass any amount of arguments, regardless of the function's "signature", because the only thing that identifies a function in JS, is its name (and the object on which it is called). That is why, the arguments object exists.
So, as others pointed it out, the second, third, or any other argument that wasn't given will simply be undefined.
An answer on this subject with examples
In ,JavaScript function parameters are optional.If your'e not making use of 'a' inside your function then JS compiler don't care about that.If your'e making use of 'a' inside your function then you will encounter some error like "a is undefined".
function (x,a=10){
}
You can set default parameters like this.Now even if your'r passing one parameter to your function it will run without any errors
I was curious so tried to understand this a bit so I could try to answer.
The variable _8x80a1 is a literal bit definition (https://www.hexadecimaldictionary.com/hexadecimal/0x80A1/) representing e.g. 32929 in decimal.
I'm guessing JS internally numbers all functions when its run. This leaves an entire integer (32766) 'vanilla' functions that can be compiled before using a literal as a function name might cause a conflict.
So the 'x' in the function def. looks like it's passing a string, but it might be just calling 'Function #0' in the _8x80a1 var/function. This would make sense if the function contains multiplpe 'sub functions', as then the 'a' variable can be an object collection (e.g. parameters), that can be passed to the sub-function.
Roughtly, I think .. Not used JS for a whilst and just thought I'd try to help answer! ;-) Essentially a compact way to make a toolkit you can copy between projects, and know your references will all work as expected to your tools, without disrupting e.g. jQuery or other scripts. (Wouldn't be surprised if this is how JS is minified actually ;)).
Chris
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]()
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.
numbers = [1,2,3,4,5,4,3,2,1];
var filterResult = numbers.filter(function(i){
return (i > 2);
});
I don't understand how this works. if I omit the i as a function argument it breaks the function but the i isn't tied to anything so why does it need to be there?
.filter (Array.prototype.filter) calls the supplied function with 3 arguments:
function(element, index, array) {
...
element is the particular array element for the call.
index is the current index of the element
array is the array being filtered.
You can use any or all of the arguments.
In your case, i refers to the element and is used in the body of your function:
function(i){
return (i > 2);
}
In other words, "filter elements where element is greater than 2".
i is a reference to the current object in the set when inside that closure. It could be named anything as it is just a variable, but then would have to have the same name inside the closure. Instead of using function(){} you could use a callback which is how filter was designed.
The reference is done implicitly by the definition of .filter, you can read more here: http://msdn.microsoft.com/en-us/library/ff679973(v=vs.94).aspx
The i is actually very important. It tells gives the filter function information about the elements it's acting on. In fact it's used right here (i > 2).
This keeps elements whose value is greater than 2.
That i is the formal parameter for the function you are supplying to .filter(). If you do not insert it, the function will not have any way¹ to refer to the argument it's being passed (the i inside the function body will then refer to some other entity that might not even be defined -- window.i would be typical).
¹ that is technically a lie, but consider it true for the purposes of this discussion
An old thread indeed, but just filling in what remains unsaid.
The parentheses are there for you the programmer to insert whatever variable name makes sense for your specific program.
If you choose 'i', most other (beginner) programmers might think 'Oh, i means index'. Which would be wrong.
If you use one argument instead of three, I'd choose 'el' to represent the element, or if your array contains flavors of soda, I'd choose 'flavor'.
That's ES5 notation and maybe if you see it in ES6 notation you would understand why the "i" is a must:
numbers.filter(i => i > 2);
A variable must always be used to refer to the item of the array that you process in each iteration (in this case "i"). It has to be passed as argument to the entry point of the function (in ES6 that goes before the arrow).