Arrays in apps script have .forEach(), .filter(), .reduce(), and .map() functions. However, using those in place of for loops won't make a difference in terms of how fast this runs. You need to take a different approach to reduce the complexity (how many operations are being performed). As written, the inner most part of that code would run 1,200,000 times given the size of the data you described.
It's also really hard to suggest an alternative approach without knowing what the problem is you're trying to solve. Does your output require the empty arrays for things you don't find? Is there meaning to the order of the output? And if there is, could that meaning be expressed differently? If you could restate what you're trying to do in simple terms that would help a lot.
For example, if the problem were "Assuming arr2 is an array of rows, return all the values in the last column where the value of the first column is in the set arr1" then you could do something like:
function seek(arr1, arr2) {
// Convert arr1 to a map keyed by value for fast lookup
var keys = arr1.reduce(function(obj, value) {
obj[value] = true;
return obj;
}, {})
return arr2.reduce(function(foundValues, row, index) {
if (keys[row[0]] !== undefined) {
foundValues.push(row[3]);
}
return foundValues;
}, []);
}
If you need to know *which* row in arr2 contained the value, then instead of pushing just the value, push an array or object like:
foundValues.push({index: index, value: row[3]});
I did a quick test and with that size data an approach like this is still fast. Anyway, can't help without knowing more about the problem, but hope that gets you on a better track :)