通过引用传递字符串作为参数

Posted

技术标签:

【中文标题】通过引用传递字符串作为参数【英文标题】:Passing string as parameter by reference 【发布时间】:2018-08-13 10:48:49 【问题描述】:

我想改变函数中字符串的内容,例如

function appendSeparating(s, s2, separator) 
    if (s != "")
        s += separator;
    s += s2;

我想在返回时更改 s,但由于字符串是一个原始值,因此按值传递,因此修改不会影响原始值。

解决这个问题的最有效/最干净的方法是什么? (我尽量保持代码简洁)

【问题讨论】:

您可以让函数返回新字符串。 javascript 总是按值传递。 制作方法并返回新值?没有真正的神奇解决方案。 一旦你返回新的字符串,你总是可以将原始字符串的内容设置为你的函数返回的字符串 【参考方案1】:

如果这就是您的意思,JavaScript 没有 out 参数。处理这个问题的最简单方法是在对象中传递字符串。

function appendSeparating(stringObj, s2, separator) 
    if (stringObj.text != "")
        stringObj.text += separator;
    stringObj.text += s2;

【讨论】:

【参考方案2】:

你可以返回新的字符串。

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', ', '));

使用对象,您可以获取对象、分离的键和其他部分并更新此属性。

function appendSeparating(object, key, s2, separator) 
    object[key] += object[key] && separator;
    return object[key] += s2;


appendSeparating(clients[index].address, 'postalCode', 'foo', ', ');

【讨论】:

是的,但是让我烦恼的是一些复杂的语句,例如 clients[index].address.postalCode=appendSeparating(clients[index].address.postalCode,"whatever",",")。 (必须重复字符串语句会触发我的懒惰,我觉得它太乱了:-) 在这种情况下,您有一个对象引用,您可以通过分离对象和键来处理它,并执行您需要的操作并更新对象并返回实际值。【参考方案3】:

here 提出了类似的问题,答案包括实现替代方案。

长话短说:将你想“通过引用传递”的字符串包装在一个对象中,然后修改该对象,如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);

【讨论】:

【参考方案4】:

全局变量

虽然字符串原语不是通过引用传递的,但没有提到的一个选项是使用全局变量的能力。凭我自己的良心,我必须建议不要这样做,但不知道你的用例你应该知道你的选择:

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;

返回作业

当然,您可以构建自己的函数并将返回变量用作赋值。下面我使用了一个原型函数,但也应该建议不要这样做,没有完全理解其含义(经验可能需要数年)——你可能会看到我在教你什么不该做:

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)

这里有一个“更好”的方法来做同样的事情。尽管效率很高,但未经训练的眼睛可能很难理解函数体中发生了什么。这是主观的,但为了可维护性,您可能希望使某些内容更具可读性:

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 || '|')
;

对象变异/作用域

您可以做的最后一件事是修改一个对象。这不仅会接近您想要的效果,而且在较大的应用程序中,对象中的变量范围非常好,以避免冲突并简化调试(但以性能损失为代价):

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 || '|')
;

【讨论】:

以上是关于通过引用传递字符串作为参数的主要内容,如果未能解决你的问题,请参考以下文章

切换基于模板类型 C++ 的引用参数传递

如何通过引用传递子字符串?

将字符串引用作为参数传递时出现错误的 Ptr

C语言中如何将二维字符数组作为函数参数引用传递

c# 值传递 引用传递

通过引用递归传递对象? JAVA