Passing arguments to Array.forEach callback function - javascript

someOperation.then(function(x) {
things.forEach(function(thing) {
//doing something with 'thing' that depends on variable 'x'
});
});
In the code above, how can I make the variable 'x' available inside the callback function? Or do I have to go back to using a for loop in this case?

It is available.
let x = {
name: 'Mike'
};
['Hello', 'Goodbye'].forEach(function(greeting) {
document.querySelector('pre').innerHTML += greeting + ', ' + x.name + '\n';
});
<pre></pre>
What you're using here is known as a closure and is a commonly used feature of Javascript. Basically, any function has access to any other variable in it's parent scope.
function log(msg) {
document.querySelector('pre').innerHTML += msg + '\n';
}
var global = 'global';
function firstLevel(third) {
var first = 'first';
// `global` is in the parent scope so we can access it
log(global + ' -> ' + first);
function secondLevel() {
var second = 'second';
// Same thing with `first` here
log(global + ' -> ' + first + ' -> ' + second);
// This even works with passed in arguments
log(global + ' -> ' + first + ' -> ' + second + ' -> ' + third);
// We can even change closed over variables
first = 'fourth?';
}
secondLevel();
log(first); // Notice that `first` changed.
}
log(global);
firstLevel('third'); // Notice how `third` is used in `secondLevel`
<pre></pre>

You can pass a "thisArg" as the second parameter to forEach so for instance:
let x = { a: 123 };
things = ['foo', 'bar']
things.forEach(function(thing) {
alert( this.a + thing );
}, x);
Might be helpful depending on what you are trying to do.

Related

Can't attach frida function to android native lib function

I'm building a frida js script that reads a json object containing directives to where to attach frida functions inside a native lib in an android APK. If I hardcode the libname and function name I can successfully attach to the function when it runs inside the app but for some reason I don't know why when I read the names from the json object the attachment doesn't occur. Assuming that I want to attach to a function named Java_sg_vantagepoint_uncrackable3_CodeCheck_bar inside libfoo.so.
The code that runs successfully:
Interceptor.attach(Module.findExportByName("libfoo.so", "Java_sg_vantagepoint_uncrackable3_CodeCheck_bar"), {
onEnter: function(args){
console.log('libfoo.so::Java_sg_vantagepoint_uncrackable3_CodeCheck_bar')
// this is logged when the function runs in the APP
if(args){
for(var arg in args){
console.log('args[' + arg + ']:')
console.log('Java_sg_vantagepoint_uncrackable3_CodeCheck_bar::args[arg] ' + args[arg])}
}
},
onLeave: function(args){
console.log('Leaving Java_sg_vantagepoint_uncrackable3_CodeCheck_bar...')
}
}
)
The code that doesn't work:
var params = {
"libs": ["libfoo.so"]
}
for(var lib in params.libs)
{
const currentLib = params.libs[lib]
Module.ensureInitialized(currentLib)
console.log('current lib: ' + currentLib)
var libExports = Module.load(currentLib).enumerateExports()
for(var i in libExports)
{
var currentLibExport = libExports[i]
if(currentLibExport.name.toLowerCase().includes('java'))
{
console.log('attaching to export: ' + currentLib + '::' + currentLibExport.name + ' at address: ' + currentLibExport.address)
Interceptor.attach(currentLibExport.address, {
onEnter: function(args){
console.log('onEnter ' + currentLib + '::' + currentLibExport.name)
if(args){
for(var arg in args){
console.log(currentLib + '::' + currentLibExport.name + '::args[arg] ' + args[arg])
}
} else
{
console.log('no args for ' + currentLib + '::' + currentLibExport.name)
}
},
onLeave: function(args){
console.log('onLeave ' + currentLib + '::' + currentLibExport.name )
}
}
)
}
}
}
Not only this doesn't attach to the function named Java_sg_vantagepoint_uncrackable3_CodeCheck_bar but even stranger during runtime it is logged the following:
onEnter libfoo.so::main
onLeave libfoo.so::main
which for me makes no sense because I didn't attach to the main function
Reference: https://www.frida.re/docs/javascript-api/#module

Loop inside loop producing wrong result

I'm having trouble producing a script to match an object's value in object array based on an object's value in a separate array, and retrieve a separate value from that object.
I have used standard for-loops and the current iteration in jQuery each.
I have also tried setting the if statement to look for the two values as ==, but it always produces non matches (or -1).
Can anyone steer me in the right direction here?
transfers = [
{Package: "1", Origin_Facility = "a"},
{Package: "2", Origin_Facility = "b"}
];
storeData = [
{fromPackage: "1,6,26"}
]
var storeDataEach = function( sx, sxv ) {
var transfersEach = function( sy, syv ) {
if(storeData[sx].fromPackage.indexOf(transfers[sy].Package) > -1){
var facilityStore = transfers[sx].Origin_Facility;
storeData[sx].origin = facilityStore + " + " + transfers[sy].Package + ' + ' + storeData[sx].fromPackage;
return false;
} else {storeData[sx].origin = 'error' + transfers[sy].Package + " + " + storeData[sx].fromPackage;return false;}
};
jQuery.each(transfers, transfersEach);
}
jQuery.each(storeData, storeDataEach);
The main problem is you are returning false from the $.each loop which will stop the iteration
A crude fix is to remove the return from else block
var storeDataEach = function(sx, sxv) {
var transfersEach = function(sy, syv) {
if (storeData[sx].fromPackage.indexOf(transfers[sy].Package) > -1) {
var facilityStore = transfers[sx].Origin_Facility;
storeData[sx].origin = facilityStore + " + " + transfers[sy].Package + ' + ' + storeData[sx].fromPackage;
return false;
} else {
storeData[sx].origin = 'error' + transfers[sy].Package + " + " + storeData[sx].fromPackage;
}
};
jQuery.each(transfers, transfersEach);
}
But this still have problems with the data structure, in your example you have 26 in the fromPackage, now if you have a package value of 2 that also will return a positive result

What will happen if I define more than one parameter but only pass in one parameter?

The function was defined as follow, but I don't know how the function will work if I pass in only one parameter and ignore the order.
function setCookie(name,value,path,expires){
value = escape(value);
if(!expires){
var now = new Date();
now.setMonth(now.getMonth() + 6);
expires = now.toUTCString();
}
if(path){
path = ";path = " + path;
}
document.cookie = name + "=" + value + ";expires = " + expires + path;
}
The rest will be undefined.
This would have been a good thing to try out on your own before asking. You could have written a test program and tested it in probably the same amount of time it took you to write the question.
Ommitting parameters to a JS function implicitly sets them to undefined. Extra parameters are ignored.
This is often used to provide default arguments (prior to ES6), like so:
function foo(bar) {
if (bar === undefined) bar = "default";
console.log(bar);
}
foo("test"); // logs "test"
foo(); // logs "default"
It will work for the most part, but you need to make sure each variable you use is defined. In the line, function setCookie(name,value,path,expires){, name, value, path, expires are all being defined right there. Its pretty much the same as var name =..., getting set to whatever you passed in. But if you don't pass anything in, it leaves out the part that defines name or the other variables, leaving those variables = undefined. When you have a variable equal to undefined, you can't use it in lines like document.cookie = name + "=" + value + ";expires = " + expires + path;. What you need to do is make sure that each one exists, and if it doesn't, define it as, in this case, a blank string.
JavaScript has very loose rules when it comes to arguments. You can make input infinite arguments that the function doesn't list (though they have to be accessed through the built in arguments variable).
function showArguments() {
for(var index = 0; arguments.length >= index; index++) {
var argument = arguments[index];
var p = document.createElement('p');
p.textContent = argument;
document.body.appendChild(p)
}
}
showArguments('foo', 'test')
You can run a function asking for 10 arguments with 0, and only when you try to access a non-existent property will it error.
function foo(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) {
console.log('no error, until you try to access something like length on the undefined argument');
var length = arg1.length;
}
foo();
But because of this looseness, when you try to access arguments that should be there, undefined is returned. So in your case beside the first possible error of running escape on undefined, there should be no errors, and document.cookie will be equal to name + '=' + undefined + ';expires = ' + now.toUTCString() + undefined.
function setCookie(name,value,path,expires){
value = escape(value);
if(!expires){
var now = new Date();
now.setMonth(now.getMonth() + 6);
expires = now.toUTCString();
}
if(path){
path = ";path = " + path;
}
var cookie = name + "=" + value + ";expires = " + expires + path;
var div = document.createElement('div');
var p = document.createElement('p');
var p2 = document.createElement('p');
p.textContent = 'name + "=" + value + ";expires = " + expires + path: ' + cookie;
p2.textContent = 'name + "=" + undefined + ";expires = " + now.toUTCString() + undefined: ' + name + "=" + undefined + ";expires = " + now.toUTCString() + undefined;
div.appendChild(p);
div.appendChild(p2);
document.body.appendChild(div);
return cookie
}
setCookie('foo');
To set a default for these undefined variables add var foo = foo || 'default'.

How can I stop my function from returning "Reference error: (...) is not defined"

I've got this code and it's returning that reference error, but I have no idea why, I've seen lots of Q&As about reference errors, but I still can't find it. Any help is appreciated.
Thanks in advance and may the force be with you.
My code:
var data = '[{"name":"node1","id":1,"is_open":true,"children":[{"name":"node2","id":6,"children":[{"name":"child3","id":7}]},{"name":"child1","id":2}]}]';
var dadSon = [];
(function printDadSon(data, parent) {
if (!data) return;
for (var i = 0; i < (data.length); i++) {
if (parent && parent != 'undefined') {
console.log('Dad: ' + parent + ' & Son: ' + data[i].id);
dadSon += ('Dad: ' + parent + ' & Son: ' + data[i].id);
}
printDadSon(data[i].children, data[i].id);
}
})(JSON.parse(data));
printDadSon(data);
You're only declaring the function in the scope of your immediately called named function expression.
So it's not visible on the line after, when you call it.
You could choose to declare the function as in
var data = '[{"name":"node1","id":1,"is_open":true,"children":[{"name":"node2","id":6,"children":[{"name":"child3","id":7}]},{"name":"child1","id":2}]}]';
var dadSon = [];
function printDadSon(data, parent) {
if (!data) return;
for (var i = 0; i < (data.length); i++) {
if (parent && parent != 'undefined') {
console.log('Dad: ' + parent + ' & Son: ' + data[i].id);
dadSon += ('Dad: ' + parent + ' & Son: ' + data[i].id);
}
printDadSon(data[i].children, data[i].id);
}
}
printDadSon(JSON.parse(data));
But you don't need to call it after, the line after is useless (and wrong in your code as you don't parse the JSON), just use
var data = '[{"name":"node1","id":1,"is_open":true,"children":[{"name":"node2","id":6,"children":[{"name":"child3","id":7}]},{"name":"child1","id":2}]}]';
var dadSon = [];
(function printDadSon(data, parent) {
if (!data) return;
for (var i = 0; i < (data.length); i++) {
if (parent && parent != 'undefined') {
console.log('Dad: ' + parent + ' & Son: ' + data[i].id);
dadSon += ('Dad: ' + parent + ' & Son: ' + data[i].id);
}
printDadSon(data[i].children, data[i].id);
}
})(JSON.parse(data));
The advantage of the second version is that it doesn't pollute the external scope with a function declaration that you don't need.
printDadSon is created using a named function expression.
Named function expressions create a variable (matching their name) in their own scope.
printDadSon(data[i].children, data[i].id);
The above line is in the scope of the function, so it can access that variable.
printDadSon(data);
The above line is not.
However, it is passing a string and the earlier line ((JSON.parse(data)) is already calling it with an actual array, so just remove that line because it isn't doing (or trying to do) anything useful.

$.post and $.get only letting title be changed, not logging?

In the following snippet of my code, I post to a link, from which it allows me to change the title, but will not call the function info() with the argument supplied, nor will it log in the console, please help with this code, thanks. Also, please note all the variables are defined and this code works 100% besides this, and it won't work with $.get rather than $.post either.
function info(text, state) {
$("<h4>"+text+"</h4>").appendTo("body");
if (state != "run") {
$("h2").text(text).fadeIn("slow").delay(30000).fadeOut();
}
$.post(buy, function(r) {
diff = event.timeStamp - last;
$(document).prop('title', 'Purchased '+info['itemName']+'!');
info('Purchased '+info['itemName']+' for '+info['expectedPrice']+' in '+diff+' milliseconds!');
console.log('Purchased '+info['itemName']+' for '+info['expectedPrice']+' in '+diff+' milliseconds!');
})
--EDIT--
If I put console.log above info, the code works excluding the info() function, so the problem is possibly there
Try (this pattern)
// var last = $.now();
function info(text, state) {
$("<h4>" + text + "</h4>").appendTo("body");
if (state != "run") {
$("h2").text(text).fadeIn("slow").delay(30000).fadeOut();
}
// missing closing `{` at OP
};
$.post(buy, function (_info) {
// `_info` : return json object
// `info` : function declaration name
// diff = $.now() - last;
$(document).prop('title', 'Purchased ' + _info['itemName'] + '!');
info('Purchased '
+ _info['itemName'] + ' for '
+ _info['expectedPrice'] + ' in '
+ diff + ' milliseconds!'
, "run");
console.log('Purchased '
+ _info['itemName'] + ' for '
+ _info['expectedPrice'] + ' in '
+ diff + ' milliseconds!');
});
jsfiddle http://jsfiddle.net/guest271314/7vxb7336/

Categories

Resources