I have a JavaScript function that takes two required parameters and then arbitrarily many optional parameters.
function myFunction(required1, required2) {
var more = [];
for (var i = 2; i < arguments.length; ++i)
more.push(arguments[i]);
// ...
}
Now, I like enforcing a consistent style through all my code. Since my site uses jQuery, and jQuery favors using $.each and $.map over explicit loops, I want to get rid of the explicit loop in myFunction. However, I cannot use either $.each or $.map because I don't want to copy the whole argument list, lest I do the following:
var more = $.map(arguments, function(argument, index) {
return (index < 2) ? null : [argument];
});
Which is, of course, a very bad idea, because testing whether index < 2 in every iteration is unnecessary.
I would really like to be able to extract a subset of the arguments object into a new array, using a standard function. However, because arguments is not an array, I cannot slice it.
Is there any other way I could extract into an array all arguments but the two first ones, without using an explicit loop, and without losing efficiency?
Using the slice method:
var optional_arguments = Array.prototype.slice.call(arguments, 2);
We have to call it from Array.prototype because, even though arguments is array-like, it doesn't actually have a slice method.
The arguments of a function can be treated like an array with jQuery, for instance the following works perfectly fine:
function something(ar1,ar2){
var args = $(arguments).slice(2);
$(args).each(function(i){
$('#stuff').append(args[i]+'<br />');
});
}
$(function(){
something('one','two','three','four');
});
And to tailor it to your function above it would look like this:
function myFunction(required1, required2) {
var more = [];
var args = $(arguments).slice(2);
$(args).each(function(i){
more.push(args[i]);
});
}
Related
No jQuery please!
The Web says that the native String.concat() and join() functions of JS are to be avoided because of their poor performance, and a simple for() loop of += assignments should work a lot faster.
So I'm trying to create a function in pure JavaScript that will concatenate strings. This is somewhat how I envision it:
I want a main function concatenate() that will concatenate all passed arguments and additionally insert a variable string after each concatenated argument, except for the last one.
If the main function is called by itself and without the chained .using() function, then that variable string should be an empty one, which means no separators in the result.
I want a chained sub-function .using() that will tell the main concatenate() function what certain string other than the default '' empty string to add after each concatenated segment.
In theory, it should work like this:
concatenate('a','b','c'); /* result: 'abc' */
concatenate('a','b','c').using('-'); /* result: 'a-b-c' */
I want to avoid having two separate functions, like concatenate() and concatenateUsing(), because the concatenateUsing() variant would then have to utilize a special constant argument (like arguments[0] or arguments[arguments.length-1]) as the injected separator and that would be terribly untidy. Plus, I would always forget which one it was.
I also want to avoid having a superceding Concatenate object with two separate sub-methods, like Concatenate.strings() and Concatenate.using() or similar.
Here are some of my failed attempts so far...
Attempt #1:
function concatenate()
{
var result="";
if(this.separator===undefined){var separator=false;}
for(var i=0; i<arguments.length; i++)
{result += arguments[i] + ((separator && (i<arguments.length-1))?separator:'');}
this.using=function(x)
{
this.separator=x;
return this;
}
return result;
}
So what I'm trying to do is:
check if the separator variable is undefined, this means it wasn't set from a sub-method yet.
If it's undefined, declare it with the value false for later evaluation.
Run the concatenation, and if separator has another value than false then use it in each concatenation step - as long as it's not the last iteration.
Then return the result.
The sub-method .using(x) should somewhere along the way set the
value of the separator variable.
Naturally, this doesn't work.
Attempt #2:
var concatenate = function()
{
var result="";
var separator="";
for(var i=0; i<arguments.length; i++)
{result += arguments[i] + ((separator && (i<arguments.length-1))?separator:'');}
return result;
}
concatenate.prototype.using=function(x)
{
this.separator=x;
return this;
}
It also doesn't work, I assume that when this is returned from the using() sub-method, the var separator="" of the main concatenate() function just overwrites the value with "" again.
I tried doing this 4 or 5 different ways now, but I don't want to bore you with all the others as well.
Does anyone know a solution for this puzzle?
Thanks a lot in advance!
What you are trying to do is impossible.
You cannot chain something to a method call that returns a primitive, because primitives do not have (custom) methods1.
And you cannot make the first function return different things depending on whether something is chained or not, because it doesn't know about its call context and has to return the result before the method call is evaluated.
Your best bet is to return an object that can be stringified using a custom toString method, and also offers that using thing. It would be something along the lines of
function concatenate() {
return {
args: Array.from(arguments), // ES6 for simplicity
using: function(separator) {
return this.args.join(separator);
},
toString: function() {
return this.args.join("");
}
};
}
console.log(String(concatenate('a','b','c')); // result: 'abc'
// alternatively, use ""+… or explicitly call the ….toString() method
console.log(concatenate('a','b','c').using('-')); // result: 'a-b-c'
1: No, you don't want to know workarounds.
I am writing a Javascript function to count the number of instances of an element in an unsorted array. It has a method signature like this
Array.prototype.numberOfOccurrences = function() {
}
Here is an example of expected behavior
var arr = [4, 0, 4];
Test.assertEquals(arr.numberOfOccurrences(4), 2);
My problem is that I don't know how to access the elements in the array. The function doesn't take any parameters so how do I reference the array being passed in?
Note: The instructions aren't very descriptive for this kata on code wars and adding a parameter to the function returns some error unexpected token.
Inside the function you are creating into the Array.prototype you can access all the prototype functions through the "this" keyword.
Meaning you can access the array items using numeric properties like this[0] or this[1] to a access the first and second item respectively.
You can also call functions which allows you to iterate over each item on the array, such as: forEach, filter, etc.
Please refer this page to see everything you can do with the array prototype:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/prototype
Lastly don't forget that the JavaScript implementation varies on each browser, so a function that works on Chrome, might not work on InternetExplorer, always confirm on caniuse.com If the function you are used has the same implementation on your targets browsers.
Cheers.
Whether you should extend javascript base objects aside, this is your friend:
Array.prototype.numberOfOccurrences = function(valueToFind) {
return this.filter(function(item) {
return item === valueToFind;
}).length;
}
var a = [1,2,3,3,3,3];
console.log(a.numberOfOccurrences(3)); //4
As noted above, if you're not able to change the function signature for whatever reason you can specify it as follows:
Array.prototype.numberOfOccurrences = function() {
var valueToFind = arguments[0];
...
}
I would recommend adding the parameter to the function for clarities sake. Seems counter intuitive for a function like numberOfOccurences to not take in a parameter - numberOfOccurences of what?
Fiddle: http://jsfiddle.net/KyleMuir/g82b3f98/
You might try using the locally available variable 'arguments' inside of the function. So for example, your code might look like thsi:
Array.prototype.numberOfOccurrences = function() {
var args = arguments || {};
var testArray, testCheck;
if (args[0] && Array.isArray(args[0]) {
// do something with the array that was the first argument, like:
testArray = args[0];
testCheck = testArray.indexOf(args[1]);
return testCheck;
} else {
// do what you want to do if the function doesn't receive any arguments or the first argument
// received isn't an array.
}
}
'arguments' is always available to you inside a declared function.
I build a objects source in JavaScript.
Is there any way to call some methods in one line like this:
var x = new object("aaa").method_a().method_b().method_c();
If you want to chain function call's you need to return this from your functions
function method_a(){
// do something
return this;
}
Same for other functions -
then you can do var x = new object("aaa").method_a().method_b().method_c();
The way to do that is making each method to return the object itself. For example:
function Person() {};
Person.prototype.setName=function(n){
this.name=n;
return this;
}
Person.prototype.setAge=function(a) {
this.age=a;
return this;
}
var p= new Person().setName("John").setAge(20);
The obvious gotcha is you cannot do that if the method has to return any other value (you can do it with setters but not with getters)
If your object doesn't support a fluid interface you can always wrap that functionality on top of it:
function FluidWrapper(obj)
{
var o = {};
for (var p in obj) {
if (typeof obj[p] == 'function') {
o[p] = function(method) {
return function() {
obj[method].apply(obj, [].slice.call(arguments, 0));
return o;
};
}(p);
}
}
return o;
}
var x = new object("aaa");
FluidWrapper(x).method_a().method_b().method_c();
Demo
While Mohammad Adil's answer is the most common scenario, i feel that the possibilities haven't been explored properly.
A function returns a value. In JavaScript you can call methods on any value except null and undefined. This means that this is perfectly acceptable:
var x = 987654321;
var y = x.toString().split('').sort().join('0');
In this scenario,
the toString() method was called on a Number who's internal value is 987654321 and returns a string.
the split('') method was called on a String who's internal value is '987654321' and returns an Array.
the sort() method was called on an Array holding the following values:['9','8','7','6','5','4','3','2','1'] and returns the same Array (but sorted).
The join('0') method was called on the same Array, but holding the values ['1','2','3','4','5','6','7','8','9'] and returns a string.
finally, after all these operations, y contains the value '10203040506070809';
So it is not necessary for the object the chained methods act on to be the same, as long as you are aware at every step of what that object is.
When you have a method called on an object, inside that method this will refer to the object. So if you return this;, then another method of that object can be called afterwards.
It is important to note that sometimes you want to return a new object of the same type rather than change the object and return it. Both work equally well when chaining, but the results are different when not. Consider the following jQuery example:
var divs = $('div'); // all divs on the page
var marked = divs.filter('.marked'); // all marked divs on the page
marked.css('color', 'red'); // make marked divs red
Because the filter method returns a new jQuery object, the initial divs variable still contains all the divs on the page. If the filter method were to eliminate things from the jQuery object it was called on and return it, then divs would point to the same object as marked and therefore would no longer have all divs on the page.
From a chaining perspective, nothing changes between the two potential implementations (except for some throw-away objects):
$('div').filter('.marked').css('color', 'red');
Rookie JS question here:
for( var p in ['nodeName', 'nodeType', 'tagName', 'localName'] ) {
console.log( p + '=' + all[i][p] + '\n' );
}
I expected to see something like
nodeName=DIV
Instead, I get
0=undefined
Am I forced to assign the array to a variable, so that I can index into it? Is there a way to use this syntax in the for-in and retrieve the string from the array?
Thanks!
Using for..in for an array is almost always wrong. It iterates over object properties, not over values -s so in your case it yields you 0, 1, 2 and 3. It gets even worse if you decide to extend Array.prototype with custom methods (which, unlike extending Object.prototype is not a big no-go). Their names will also be iterated over when using for..in.
The proper way to do what you want is this:
var foo = [...];
for(var i = 0; i < foo.length; i++) {
// use foo[i]
}
or this (in modern browsers or with the function being shim'd):
[...].forEach(function(value) {
// use value
});
I have a Javascript object that I'm trying to use as a "hashmap". The keys are always strings, so I don't think I need anything as sophisticated as what's described in this SO question. (I also don't expect the number of keys to go above about 10 so I'm not particularly concerned with lookups being O(n) vs. O(log n) etc.)
The only functionality I want that built-in Javascript objects don't seem to have, is a quick way to figure out the number of key/value pairs in the object, like what Java's Map.size returns. Of course, you could just do something like:
function getObjectSize(myObject) {
var count=0
for (var key in myObject)
count++
return count
}
but that seems kind of hacky and roundabout. Is there a "right way" to get the number of fields in the object?
There is an easier way spec'd in ECMAScript 5.
Object.keys(..) returns an array of all keys defined on the object. Length can be called on that. Try in Chrome:
Object.keys({a: 1, b: 2}).length; // 2
Note that all objects are basically key/value pairs in JavaScript, and they are also very extensible. You could extend the Object.prototype with a size method and get the count there. However, a much better solution is to create a HashMap type interface or use one of the many existing implementations out there, and define size on it. Here's one tiny implementation:
function HashMap() {}
HashMap.prototype.put = function(key, value) {
this[key] = value;
};
HashMap.prototype.get = function(key) {
if(typeof this[key] == 'undefined') {
throw new ReferenceError("key is undefined");
}
return this[key];
};
HashMap.prototype.size = function() {
var count = 0;
for(var prop in this) {
// hasOwnProperty check is important because
// we don't want to count properties on the prototype chain
// such as "get", "put", "size", or others.
if(this.hasOwnProperty(prop) {
count++;
}
}
return count;
};
Use as (example):
var map = new HashMap();
map.put(someKey, someValue);
map.size();
A correction: you need to check myObject.hasOwnProperty(key) in each iteration, because there're can be inherited attributes. For example, if you do this before loop Object.prototype.test = 'test', test will aslo be counted.
And talking about your question: you can just define a helper function, if speed doesn't matter. After all, we define helpers for trim function and other simple things. A lot of javascript is "kind of hacky and roundabout" :)
update
Failure example, as requested.
Object.prototype.test = 'test';
var x = {};
x['a'] = 1;
x['b'] = 2;
The count returned will be 3.
you could also just do myObject.length (in arrays)
nevermind, see this: JavaScript object size
That's all you can do. Clearly, JavaScript objects are not designed for this. And this will only give you the number of Enumerable properties. Try getObjectSize(Math).