I want to alter the contents of a string in a function, for example
function appendSeparating(s, s2, separator) {
if (s != "")
s += separator;
s += s2;
}
I'd like to have s altered on return but as string is a primitive is being passed by value so the modifications do not affect the original.
What is the most efficient/clean way to deal with this? (I try to keep code concise)
I want to alter the contents of a string in a function, for example
function appendSeparating(s, s2, separator) {
if (s != "")
s += separator;
s += s2;
}
I'd like to have s altered on return but as string is a primitive is being passed by value so the modifications do not affect the original.
What is the most efficient/clean way to deal with this? (I try to keep code concise)
Share Improve this question edited Mar 5, 2018 at 17:37 Huangism 16.4k7 gold badges50 silver badges75 bronze badges asked Mar 5, 2018 at 17:31 tru7tru7 7,2426 gold badges42 silver badges71 bronze badges 3- 4 You can have the function return the new string. JavaScript is always pass-by-value. – Pointy Commented Mar 5, 2018 at 17:33
- 1 Make a method and return the new value? There is no real magical solution. – epascarello Commented Mar 5, 2018 at 17:33
- 1 You can always set the original string's content to the returned string of your function, once you return the new string – Huangism Commented Mar 5, 2018 at 17:36
4 Answers
Reset to default 7JavaScript has no out
parameters if that's what you mean. The simplest way of dealing with this is to pass the string in an object.
function appendSeparating(stringObj, s2, separator) {
if (stringObj.text != "")
stringObj.text += separator;
stringObj.text += s2;
}
Global Variables
While string primitives are not passed by reference, one option not mentioned is the ability to use global variables. Of my own conscience, I must advise against this, but not knowing your use case you should know of your options:
s = 'a' // created as a global variable
appendSeparating('b', '|') // function now takes only two arguments
console.log(s) // global variable affected
function appendSeparating(s2, separator) {
// s is a global variable
if (typeof s === 'undefined')
return;
if (s != "")
s += separator;
s += s2;
}
Return Assignment
Of course you could build your own function and use the return variable as an assignment. Below I've used a prototype function, but should also advise against this, without fully understanding the implications (experience can take years) — you may see that I'm teaching you what not to do:
String.prototype.append = function(str, delimiter) {
return [this, str].filter(v => v !== '').join(delimiter || '|')
};
let ex1 = 'a'
ex1 = ex1.append('b')
console.log('no delim: ', ex1)
let ex2 = 'a'
ex2 = ex2.append('b', '-')
console.log('w/ delim: ', ex2)
Here's a "better" way to do the same. Although efficient, the untrained eye might struggle to understand what is occurring in the body of the function. It's subjective, but for maintainability you might want to make something more readable:
let ex1 = 'a'
ex1 = append(ex1, 'b')
console.log('no delim: ', ex1)
let ex2 = 'a'
ex2 = append(ex2, 'b', '-')
console.log('w/ delim: ', ex2)
function append(prefix, suffix, delimiter) {
return [prefix, suffix].filter(v => v !== '').join(delimiter || '|')
};
Object Mutation / Scoping
The final thing you can do is modify an object. Not only will this get close to what it seems you'd like, but in larger applications is very nice to scope variables in objects to avoid collision and ease debugging (though, at the cost of a performance penalty):
const strings = {}
// Assuming key name
strings.s = 'foo'
append(strings, 'bar', ': ')
console.log(strings.s)
// Supplying key name
strings.x = 'x'
appendNamed(strings, 'x', 'y')
console.log(strings.x)
function append(str, suffix, delimiter) {
str.s = [str.s, suffix].filter(v => v !== '').join(delimiter || '|')
};
function appendNamed(str, strName, suffix, delimiter){
str[strName] = [str[strName], suffix].filter(v => v !== '').join(delimiter || '|')
};
A similar question was made here, and the answers include implementation alternatives.
Long story short: wrap the string you would like to "pass by reference" in an object, then modify the object, as shown in this fiddle
function concatStrings(stringObj, s2, separator) {
stringObj.value = stringObj.value + separator + s2;
}
var baseString = "hello";
var stringObj = {value: baseString};
var s2 = "world";
var separator = " ";
concatStrings(stringObj, s2, separator);
window.alert(stringObj.value);
You could return the new string.
function appendSeparating(s, s2, separator) {
s += s && separator;
return s + s2;
}
var x = '';
console.log(x = appendSeparating(x, 'one', ', '));
console.log(x = appendSeparating(x, 'two', ', '));
console.log(x = appendSeparating(x, 'three', ', '));
With an object, you could take the object, the separated key and the other parts and update this property.
function appendSeparating(object, key, s2, separator) {
object[key] += object[key] && separator;
return object[key] += s2;
}
appendSeparating(clients[index].address, 'postalCode', 'foo', ', ');