JavaScript passing argument via reference - javascript

let say I've got this kind of code:
var obj1 = {test: false};
function testCondition(condition){
if (!condition){
testCondition(condition);
}
}
testCondition(obj1.test);
above code will pass false as argument to testCondition. How can I do to pass reference to obj1.test instead of passing it's value?
EDIT
wow, thanks for quick responses!! :) But I would like to add, that I cannot pass the whole object, because I would like to build one generic function/method which would just check parameter and do onComplete callback or onError callback. Above code is only example of situation where I am right now.

You have two choices, from what I can see:
Pass the object itself, instead of its member. You can then access and modify the member:
function testCondition(object) {
if (!object.test) {
testCondition(object);
}
}
testCondition(obj1)
Alternatively, since you're changing a single value, you can have that value be returned by the function:
function testCondition(condition) {
if (!condition){
return testCondition(condition);
}
}
obj1.test = testCondition(obj1.test);
FYI, your code as you've displayed it right now will cause an infinite recursion if condition is false.

What's wrong with return values?
Alternatively you can wrap the argument in an object:
function foo(arg) {
var val = arg.val;
// do something with val
arg.val = val;
}
var arg = {val:"bar"};
foo(arg);
// do something with arg.val

You can't.
Pass obj1 instead, then examine condition.test inside the function.

You can't. JavaScript passes objects and arrays by reference, primitives (integers, strings, booleans) by value. What you're asking for is impossible, except by bad work-arounds:
function ugly(result) {
result.success = true;
}
var result = {};
ugly(result);
Instead, just return your value. It's how JavaScript is meant to work.

pass the whole object instead of its property:
testCondition(obj1);
and then
if(!passedObj.test){
etc...

Related

array.splice = what does it means?

I would like to understand the meaning of that code fragment. "saveTo" is a array, the programmer assigned a function() to the splice method. I don't understand what does it mean. Is that a override? What is the meaning of the return argument?, and why the function takes no argument while splice requires 2 or more arguments?
saveTo.splice = function() {
if (saveTo.length == 1) {
$("#send").prop("disabled", true);
}
return Array.prototype.splice.apply(this, arguments);
};
Javascript lets you re-assign methods at runtime. In this case, what the programmer was doing is reassigning splice on this specific instance of an array in order to call a jQuery method. Beyond that, it works in exactly the same way as the existing splice as they are calling return Array.prototype.splice.apply(this, arguments); - meaning that this method just passes on whatever arguments are passed to it.
Here's a demo:
var myArray = [1,2,3,4];
console.log("Splice before re-assing: ", myArray.splice(1,1));
// reset it.
myArray = [1,2,3,4];
myArray.splice = function(){
console.log("From inside new splice function");
return Array.prototype.splice.apply(this, arguments);
}
console.log("Splice after re-assiging: ", myArray.splice(1,1));
Whether this is a good thing to do is debatable. It breaks a few principles of programming.
The programmer that wrote this code knew that some other part of the program is calling splice on this array, and he wanted to attach an event to that, in order to update the user interface (hence the call to jQuery).
This is commonly called "Monkey Patching". You can read about it at https://www.audero.it/blog/2016/12/05/monkey-patching-javascript/
This is not a good pratice as it obfuscate what is happening: no programmer would expect that calling a data manipulation function has side-effects somewhere else.
You can run this sample to understand how it works:
const myArray = [];
// Patch push method only for this instance of array.
myArray.push = function() {
// log event
console.log('myArray.push was called with the following arguments', arguments);
// Call the original push function with the provided arguments.
return Array.prototype.push.apply(this, arguments);
}
myArray.push(1);
You can also patch methods for all instances of a given class:
// Patch push method on all arrays
const originalPush = Array.prototype.push;
Array.prototype.push = function() {
// log event
console.log('.push was called with the following arguments', arguments);
// Call the original push function with the provided arguments.
return originalPush.apply(this, arguments);
}
const myArray = [];
myArray.push(1);
As for your question about the arguments, in javascript all functions can access the arguments array-like object that contains the arguments the function was called with, which does not depend on which arguments are specified in the original declaration.
function doSomething(arg1) {
console.log(arguments[2]);
}
doSomething(1, 2, 3); // outputs "3"
Here is the MDN documentation about it: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments
Note that there is a better way to extend arrays in ES6:
class CustomArray extends Array {
splice(...args) {
if(this.length === 1) {
$("#send").prop("disabled", true);
}
super.splice(...args);
}
}
Now that there are other ways to change the arrays length, .length, .pop, .shift, etc. so those should be overriden as well. However then it is still questionable wether the code calling those methods should not just cause the side effect.
What this does is it adds some checks for specifically saveTo.splice. If you call anyOtherArray.splice, then it'll just be evaluated as per normal. The reason it takes no arguments is because Array.prototype.splice takes arguments, and also the calling context of saveTo, as well as the array-like objects arguments, representing all the arguments passed to saveTo.splice. So it's just adding a little bit of extra code based on a specific condition - other than that, there's no difference to the native splice.
1) Yes, the programmer has overridden splice method, its not recommended
2) return statement is nothing but calls Array.prototype.splice(the original method).
3) Yes, splice requires arguments, but in JS, you may not define them as function params. You get the passed parameters as an array like object arguments inside your functions,
if you look closely, they call Array.prototype.splice with this and arguments object.
Okay, let's dissect this piece by piece.
saveTo.splice = function() {
if (saveTo.length == 1) {
$("#send").prop("disabled", true);
}
return Array.prototype.splice.apply(this, arguments);
};
As we all know that in JavaScript functions are first class objects, so if we have an object let's say saveTo something like this:
const saveTo = {};
Then we can assign a function to one of its properties like :
saveTo.splice = function() {
};
or something like this to:
const saveTo = {
splice: function() {
}
};
With that out of the way, you are just calling the Array#prototype#splice method to create a shallow copy out of the array and passing it an iterable to it.
So in total you have overridden the native Array#prototype#splice to fit your requirement.

Accessing parameters when the function expects none Javascript

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.

Creating .invoke() from scratch. Why does function work but method returns undefined?

I'm doing precourse work for a JavaScript-based programming school and I've run into a problem. The
assignment is to rewrite some underscore.js methods from scratch so we know how they work, rather than just relying on them blindly. My _.invoke will pass functions refs but not method names.
Here's the original problem:
// Calls the method named by functionOrKey on each value in the list.
// Note: you will nead to learn a bit about .apply to complete this.
_.invoke = function(collection, functionOrKey, args) {
};
My solution so far using _.map() I wrote previously (which passed its own tests):
_.invoke = function(collection, functionOrKey, args) {
return _.map(collection, function(value) {
return functionOrKey.apply(value, args);
});
};
My solution will support passing a function for functionOrKey. For example (from the Mocha Test Suite):
var reverse = function(){
return this.split('').reverse().join('');
};
var reversedStrings = _.invoke(['dog', 'cat'], reverse);
reseversedStrings = "['god', tac']; //YAY!!
However, when it comes to passing a method, such as toUpperCase, I get the error message: "TypeError: undefined is not a function". Any suggestions appreciated!
EDIT: Found the failing test:
var upperCasedStrings = _.invoke(['dog', 'cat'], 'toUpperCase');
expect(upperCasedStrings).to.eql(['DOG', 'CAT']);
My solution would be:
_.invoke = function(collection, functionOrKey, args) {
//invoke when provided a method name
if(typeof functionOrKey === 'string'){
return _.map(collection, function(val){
return val[functionOrKey](args);
});
}
//invoke when provided a function reference
return _.map(collection, function(val){
return functionOrKey.apply(val, args);
});
};
However, when it comes to passing a method, such as toUpperCase, I get the error message: "TypeError: undefined is not a function"
Well, you're not passing a "method". See #elclarns' answer for how to pass a bound function.
What you are passing is a property name, which is a string - and when functionOrKey is the string 'toUpperCase' it does not have an apply method. You will need to check the type of that parameter, and act accordingly. When it's a string, you will want to use
return value[key].apply(value, args);
in the map callback.
Btw, your args parameter shouldn't be an array, but should be built from the dynamic arguments object. If you want to "cheat" (or see the full solution), have a look at the annotated source code of Underscore.
I'm not sure I fully understand your problem, but maybe it can be simpler. If you want to call a method and invoke it for each item in the array, you could simply use the builtin map like this:
var invoke = Function.bind.bind(Function.call)
var reverse = function() {
return this.split('').reverse().join('')
}
var result = ['dog', 'cat'].map(invoke(reverse)) //=> ['god', 'tac']
You can also use it with builtin methods:
['dog', 'cat'].map(invoke(''.toUpperCase)) //=> ['DOG', 'CAT']
I think this solves your particular issue, but invoke doesn't forward any additional arguments to the function it calls, as per Underscore documentation. In that case you can try to use what you've got so far plus the above helper, and capture any additional arguments.

How do I add a new method to strings in JavaScript?

Maybe this question have beend posted before what I just do not know how to search for it.
I'd like to know how can I create a method like .replace(), or .toString(). I mean, if I have a variable and I want to search if that variable have number or not, like to do this
var someVariable = "hello 34, how are you";
var containsIntsNumber = someVariable.SearchInteger();//being search integer my custom method
if(containsIntsNumber )
{
console.log("It does have integers");
}
How can I achieve this?
You can modify the prototype on the String object.
String.prototype.someFunction = function () {
/* Your function body here; you can use
this to access the string itself */
};
You can add it to the string prototype.
String.prototype.SearchInteger = function(){
//do stuff
}
the you can call it like this
var someVariable = "hello 34, how are you";
var containsIntsNumber = someVariable.SearchInteger();
Adding additional functions to prototypes can be a bit controversial in the JS community. Be warned that it will then show up when you enumerate over the properties of the variable, and it could theoretically be overwritten or used for a different purpose by an external library.
This can be achieved in few ways. Have a function that return boolean value or extend string prototype so that you can call this method directly on string variable.
This will check wheather string has a number.
String.prototype.hasInteger = function(){
return /\d/.test(this);
}
However it is not recommended to augment native objects, so my suggestion would be just use a function.
function hasInteger(value){
return /\d/.test(value);
}
if(!String.prototype.SearchInteger)
{
Object.defineProperty(String.prototype, 'SearchInteger',
{
value: function()
{
// body of your function here
},
enumerable: false
});
}
You will have to extend the prototype of String in this case. As String is an inbuilt type, It is not recommended to extend their prototype, but you can still do if you fancy(but dont!)
easy example would be something like
String.prototype.SearchInteger = function () {
return this.test(/^.*\d+.*$/g);
};
this should work, though I didn't test.

JavaScript - referencing arguments from within a function

Recently i found myself attaching function arguments to a variable inside the function scope so that i was not referencing the argument every time it was used.
Is there any benefit to this practice?
For example:
function populateResultCount(count){
var count = count;
return $('.resultCounter').text(count);
};
Could easily be re-written like so:
function populateResultCount(count){
return $('.resultCounter').text(count);
};
And would still function correctly.
There's no functional difference between the two. Go with the simpler version.
If you're not using the argument that's passed in, there is no difference. In your first example, you can potentially confuse future maintainers because of var count = count, i.e., you're declaring a variable that has the same name as the argument, and that isn't a best practise.
So, if you can, use your second form. Its intent is clearer and there is no room for confusion.
I can see no benefit to this unless you are manipulating the data somehow. Your variable without the additional assingment can still not be accessed outside of the function.
function Test (count) {
this.increment = function() {
count++;
}
this.getCount = function() {
return count;
}
}
var test = new Test(10);
<button onclick="test.increment(); alert(test.getCount());">Increment</button>
You can do something like that even with the argument. So I think they are same.
All the other answers are correct: There's no reason to "re-assign" a passed argument inside the function.
The only thing I can think of, where you'd mess with reassigning arguments, is if you have optional arguments/default values
function xyz(optionalArgument) {
optionalArgument = optionalArgument || "no argument given";
...
}
But in that case, it'd be better to write it as
function xyz( /* optionalArgument */ ) {
var optionalArgument = arguments[0] || "no argument given";
...
}
Note that the || trick will give you the right-hand side's value, if the left-hand side is a falsy value. I.e. if you're ok with the optional argument being something that's falsy (like explicitly passing null, 0, etc), you'd have to do something like var arg = typeof arguments[x] === 'undefined' ? defaultValue : arguments[x];

Categories

Resources