How to get a slice from "arguments" - javascript

All you know that arguments is a special object that holds all the arguments passed to the function.
And as long as it is not an array - you cannot use something like arguments.slice(1).
So the question - how to slice everything but first element from arguments?
UPD:
seems like there is no way without converting it to an array with
var args = Array.prototype.slice.call(arguments);
If someone posts another solution it would be great, if not - I'll check the first one with the line above as an answer.

Q. How to slice everything but first element from arguments?
The following will return an array containing all arguments except the first:
var slicedArgs = Array.prototype.slice.call(arguments, 1);
You don't have to convert arguments to an array first, do it all in one step.

Meddling with array functions is not actually necessary.
Using rest parameter syntax ...rest is cleaner and more convenient.
Example
function argumentTest(first, ...rest) {
console.log("First arg:" + first);
// loop through the rest of the parameters
for (let arg of rest) {
console.log("- " + arg);
}
}
// call your function with any number of arguments
argumentTest("first arg", "#2", "more arguments", "this is not an argument but a contradiction");
...Rest
See the example Fiddle
See MDN Documentation page

From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments:
You should not slice on arguments because it prevents optimizations in
JavaScript engines (V8 for example). Instead, try constructing a new
array by iterating through the arguments object.
So Paul Rosiana's answer above is correct

This can be a way:
var args = Array.from(arguments).slice(1);

You can "slice without slicing" by procedurally walking the arguments object:
function fun() {
var args = [];
for (var i = 1; i < arguments.length; i++) {
args.push(arguments[i]);
}
return args;
}
fun(1, 2, 3, 4, 5); //=> [2, 3, 4, 5]

You can use the method [].slice.call(arguments, 1)
[].slice will return you the slice function object and you can call it as the arguments and 1 are the parameters

You can use ...rest within the function to separate the first and the rest of the arguments:
function foo(arr) {
const [first, ...rest] = arguments;
console.log(`first = ${first}`);
console.log(`rest = ${rest}`);
}
//Then calling the function with 3 arguments:
foo(1,2,3)

you can use this too
function arg(myArr) {
let arg = Object.values(arguments).slice(2, 4);
console.log(arg);
return arg;
};
arg([1, 2, 3], 4, [5,6], 7)
see here for reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values
...

Arguments type is iterable, so using the ES6 (ES2015) spread ... operator, then use Array.slice([start], [end]) method, such as
function omitFirstAndLastArgument(value) {
const args = arguments.length > 2 ? [...arguments].slice(1, -1) : [];
return args;
}
omitFirstAndLastArgument(1, 2, 3, 4, 5, 6); // [2, 3, 4, 5]

Related

How can i target elements in another array via .filter()

Im trying to return the values in argument[0] that are not equal to the values of arguments[1] and so on.
Ive created a variable 'let argArr' that holds the values of the arguments after the first, Im trying to understand why in my .filter() i cannot target 'let argArr'?
function destroyer(arr) {
let argArr = [];
for (let i = 1; i < arguments.length; i++) {
argArr.push(arguments[i])
}
return arr.filter(i => i !== argArr)
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));
You are comparing an arr array's element to the argArr what is wrong.
The right way is to check if element is inside argArr and filter if yes.
return arr.filter(i => !argArr.includes(i))
Instead of using arguments explicitly specify the array as the first argument, and then use rest parameters to gather all the remaining arguments into an array. Then use filter to return only those elements in the array that are not in the rest array.
function destroyer(arr, ...rest) {
return arr.filter(el => !rest.includes(el));
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));
Use spread operator to treat arguments as normal array
function foo() {
return [...arguments].filter(el => el);
}
console.log(foo(1,2,3))

Write function outputs to file in javascript [duplicate]

Let's suppose I wanted a sort function that returns a sorted copy of the inputted array. I naively tried this
function sort(arr) {
return arr.sort();
}
and I tested it with this, which shows that my sort method is mutating the array.
var a = [2,3,7,5,3,7,1,3,4];
sort(a);
alert(a); //alerts "1,2,3,3,3,4,5,7,7"
I also tried this approach
function sort(arr) {
return Array.prototype.sort(arr);
}
but it doesn't work at all.
Is there a straightforward way around this, preferably a way that doesn't require hand-rolling my own sorting algorithm or copying every element of the array into a new one?
You need to copy the array before you sort it. One way with es6:
const sorted = [...arr].sort();
The spread-syntax as array literal (copied from mdn):
var arr = [1, 2, 3];
var arr2 = [...arr]; // like arr.slice()
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator
Just copy the array. There are many ways to do that:
function sort(arr) {
return arr.concat().sort();
}
// Or:
return Array.prototype.slice.call(arr).sort(); // For array-like objects
Try the following
function sortCopy(arr) {
return arr.slice(0).sort();
}
The slice(0) expression creates a copy of the array starting at element 0.
You can use slice with no arguments to copy an array:
var foo,
bar;
foo = [3,1,2];
bar = foo.slice().sort();
You can also do this
d = [20, 30, 10]
e = Array.from(d)
e.sort()
This way d will not get mutated.
function sorted(arr) {
temp = Array.from(arr)
return temp.sort()
}
//Use it like this
x = [20, 10, 100]
console.log(sorted(x))
Update - Array.prototype.toSorted() proposal
The Array.prototype.toSorted(compareFn) -> Array is a new method which was proposed to be added to the Array.prototype and is currently in stage 3 (Soon to be available).
This method will keep the target Array untouched and returns a copy of it with the change performed instead.
Anyone who wants to do a deep copy (e.g. if your array contains objects) can use:
let arrCopy = JSON.parse(JSON.stringify(arr))
Then you can sort arrCopy without changing arr.
arrCopy.sort((obj1, obj2) => obj1.id > obj2.id)
Please note: this can be slow for very large arrays.
Try this to sort the numbers. This does not mutate the original array.
function sort(arr) {
return arr.slice(0).sort((a,b) => a-b);
}
There's a new tc39 proposal, which adds a toSorted method to Array that returns a copy of the array and doesn't modify the original.
For example:
const sequence = [3, 2, 1];
sequence.toSorted(); // => [1, 2, 3]
sequence; // => [3, 2, 1]
As it's currently in stage 3, it will likely be implemented in browser engines soon, but in the meantime a polyfill is available here or in core-js.
I think that my answer is a bit too late but if someone come across this issue again the solution may be useful.
I can propose yet another approach with a native function which returns a sorted array.
This code still mutates the original object but instead of native behaviour this implementation returns a sorted array.
// Remember that it is not recommended to extend build-in prototypes
// or even worse override native functions.
// You can create a seperate function if you like
// You can specify any name instead of "sorted" (Python-like)
// Check for existence of the method in prototype
if (typeof Array.prototype.sorted == "undefined") {
// If it does not exist you provide your own method
Array.prototype.sorted = function () {
Array.prototype.sort.apply(this, arguments);
return this;
};
}
This way of solving the problem was ideal in my situation.
You can also extend the existing Array functionality. This allows chaining different array functions together.
Array.prototype.sorted = function (compareFn) {
const shallowCopy = this.slice();
shallowCopy.sort(compareFn);
return shallowCopy;
}
[1, 2, 3, 4, 5, 6]
.filter(x => x % 2 == 0)
.sorted((l, r) => r - l)
.map(x => x * 2)
// -> [12, 8, 4]
Same in typescript:
// extensions.ts
Array.prototype.sorted = function (compareFn?: ((a: any, b: any) => number) | undefined) {
const shallowCopy = this.slice();
shallowCopy.sort(compareFn);
return shallowCopy;
}
declare global {
interface Array<T> {
sorted(compareFn?: (a: T, b: T) => number): Array<T>;
}
}
export {}
// index.ts
import 'extensions.ts';
[1, 2, 3, 4, 5, 6]
.filter(x => x % 2 == 0)
.sorted((l, r) => r - l)
.map(x => x * 2)
// -> [12, 8, 4]

How do i concat arrays with unknown amount of arguments

So I have my function uniteUnique. It should get the arguments and concatonate them to a single array. If there would be a specific amount of arguments for example 3, i would implement it like the function bellow
function uniteUnique(arr) {
var args = [];
var newArgs;
for (var i = 0; i < arguments.length; i++) {
args.push(arguments[i]);
newArgs = args[0].concat(args[1], args[2]);
}
return newArgs ;
}
uniteUnique([1, 3, 2], [1, [5]], [2, [4]]);
But what if uniteUnique function would have 2 arguments or any other number.
uniteUnique([1, 2, 3], [5, 2, 1])
How to make my function know how many arguments it should concatonate, and how would it be implemented inside the concat() function ?
EDIT:
Output should look like this:
uniteUnique([1, 3, 2], [1, [5]], [2, [4]]) should return [1,3,1,1,[5],2,[4]]and uniteUnique([1, 2, 3], [5, 2, 1]) should return [1,2,3,5,2,1]
I'm not sure if I fully understand your question, but: what about this simple solution?
function uniteUnique() {
return Array.prototype.slice.call(arguments);
}
The arguments object is not really an Array instance, and does not have any of the Array methods. So, arguments.slice(...) will not work because the arguments object does not have the slice method.
Instead, Arrays do have this method, and because the arguments object is very similar (...) to an array, the two are compatible. This means that we can use array methods with the arguments object. And array methods will return arrays rather than other argument objects.
For a more throughtful explanation please see this SO answer ...
UPDATE (to answer OP comment):
If you need deep merging, you can do:
function uniteUnique() {
return Array.prototype.concat.apply([], arrays);
}
or even:
function uniteUnique() {
return [].concat.apply([], arrays);
}
This should work since the dafaule value of Symbol.isConcatSpreadable is false, so concat() acts deeply...
According to your examples you want to flatten arguments array. In ES6 you can use Rest parameters to get arguments array and Spread syntax to flatten it:
function uniteUnique(...args) {
return [].concat(...args);
}
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/arguments
You can access the arguments variable to loop through all arguments passed to a given function.
Was able to solve this like that,
function uniteUnique(arr) {
var myNewArray = [].concat.apply([], Array.prototype.slice.call(arguments));
return myNewArray;
}
uniteUnique([1, 3, 2], [1, [5]], [2, [4]]) ;

Lodash Map with mulitvariable function

Is it possible to use lodash to iterate over a collection and pass the item to a function that requires two (or more) arguments? In the following example, the function should take two values and add them. The map should take an array and add 10 to each. The following is how I thought this worked:
function x (a, b) {
return a + b
}
var nums = [1, 2, 3]
console.log(_.map(nums,x(10)))
--->ans should be [11, 12, 13]
--->actually is [ undefined, undefined, undefined ]
What you're essentially trying to do here is "curry" the x function, which lodash supports via curry(). A curried function is one that can take its arguments one at a time: if you don't provide a full set of arguments, it returns a function expecting the remaining arguments.
This is what currying looks like:
function x(a,b) {
return a + b;
}
x = _.curry(x); //returns a curried version of x
x(3,5); //returns 8, same as the un-curried version
add10 = x(10);
add10(3); //returns 13
So your original code is very close to the curried version:
console.log(_.map([1,2,3], _.curry(x)(10))); //Prints [11,12,13]
(As was pointed out in the comment on the question; Function.prototype.bind can also be used for currying, but if you're already using lodash, you might as well use something specific to the task)
You can do it like this:
var numbers = [1, 2, 3];
function x(value, number) {
return value + number;
}
console.log(_.map(numbers, function(value) { return x(value, 10) }));
Sure, closure is awesome! Just make a function that "closes" (wraps) your x function and passes 10 as its second argument.
function x (a, b) {
return a + b;
}
function addTen (number) {
return x(numberToAddTo, 10);
}
var nums = [1, 2, 3];
console.log(_.map(nums, addTen));

A Javascript function named method

I found an implementation using using prototypes. This is a simplification to show the structure:
function Thingie(){
this.content = [];
}
Thingie.prototype = {
push: function(arg) {
this.content.push(arg);
},
pop: function() {
return this.content.pop();
}
};
var t = new Thingie();
forEach([10, 3, 4, 8, 2, 9, 7, 1, 2, 6, 5],
method(t, "push"));
What is "method" in the example on the last line? I've never seen this construct. I use t.push like everyone else.
I tried find how "method()" is defined online, but it is impossible to search for a function called "method" using any possible set of search terms. All you get are how functions and methods are defined and used. There also seems to be no information when I look at forEach documentation.
Does this make sense to anybody?
method(t, "push")
would be defined as:
function method(obj, name) {
return obj[name].bind(obj);
}
That forEach looks like UnderscoreJS's function _.each
_.each(list, iteratee, [context]) Alias: forEach
example:
_.each([1,2,3], function(item) { console.log(item); });
// console output:
// 1
// 2
// 3
That method probably looks like this (Beware: wild guess!) , giving you the function to use as iteratee paramater
function method(obj, name){
if(typeof(obj[name]) != "function")
throw new Error("Not a function");
return obj[name];
}
A function like that is lodash.bindKey, which does exactly what you want. Also, the forEach method could be lodash.forEach, or simply Array.prototype.forEach, which is built-in.
[1,2,3].forEach(_.bindKey(t, 'push'));
However, this works because Thinghie#push expects only one argument. If the same call would be made on an array, the result would not be as expected, since forEach methods take 3 arguments: value, index, array, and [].push can handle multiple arguments. So, the code
var array = [];
[1,2].forEach(_.bindKey(array, 'push'));
console.log(array); // outputs [1, 0, [1, 2], 2, 1, [1, 2]]
In this case (and in any case when we would like the function returned by method applied on only one argument), I guess the solution is to write
function method(obj, name) {
return function(arg) { return obj[name](arg); }
}

Categories