Filter array elements using variable number of filters
What didn't work, is using arr = arr.filter... to iterate over the array passed into the function


It works. But you would then need to return arr instead of newArr. Also, it is less readable as you re-assign the function's return value to the input parameter, which is confusing. 

Further suggested improvements:

Naming:


Rename newArr to e.g. result as this makes its role more clear.


Style:


Array.from(arguments).slice(1) creates an unnecessary internal copy. Use e.g. Array.prototype.slice.call(arguments, 1). Some people prefer [].slice.call(arguments, 1)
Don't make an unnecessary local copy of the arguments if performance
is key.
Since you already make a local copy, replace the for-loop with the functional style Array.includes for consistency's sake, since you already use Array.filter.
Having a function call within a loop body is slow as the function call overhead is not marginal in JavaScript.
Declare the loop iterator i as a local variable for (var i = ...


Applying those suggestions to your code gives us:



function destroyer(array) {
  var filter = Array.prototype.slice.call(arguments, 1);
  return array.filter(function(el) {
    return !filter.includes(el);
  });
}

console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3)); // [1, 1]
console.log(destroyer(["tree", "hamburger", 53], "tree", 53)) // ["hamburger"]




However, this function is inefficient for larger inputs as it iterates the filter array for each array element. It's time complexity is in O(mn) where m and n are the lengths of array and filter. You can improve on that by using a Set and come up with a linear time solution. Using rest parameters allows us to get rid of the argument slicing:



function destroyer(array, ...filter) {
  filter = new Set(filter);
  return array.filter(element =&gt; !filter.has(element));
}

console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3)); // [1, 1]
console.log(destroyer(["tree", "hamburger", 53], "tree", 53)) // ["hamburger"]