如何在JavaScript中设置/更新字符串对象的值

如何在JavaScript中设置/更新字符串对象的值,javascript,Javascript,我有一个具有一些属性的对象,这些属性是字符串对象: var obj = { foo: new String("bar") }; 我正在使用字符串对象,因为我需要在对象上存储附加的子属性,同时仍然能够获取字符串值: obj.foo.baz = "baz"; "" + obj.foo; //-> "bar"; 问这个问题我觉得很傻,但是我如何更新String对象的值呢?似乎需要应用一些阵列拼接魔术 EDIT:说清楚一点,我理解JS中的字符串原语以及其中的不变性。这是我正在谈论的对象

我有一个具有一些属性的对象,这些属性是字符串对象

var obj = {
    foo: new String("bar")
};
我正在使用字符串对象,因为我需要在对象上存储附加的子属性,同时仍然能够获取字符串值:

obj.foo.baz = "baz";
"" + obj.foo; //-> "bar";
问这个问题我觉得很傻,但是我如何更新String对象的值呢?似乎需要应用一些阵列拼接魔术

EDIT:说清楚一点,我理解JS中的字符串原语以及其中的不变性。这是我正在谈论的对象。以下是需要通过的测试:

assert.equal("" + obj.foo, "foo"); //-> true
assert.equal(obj.foo.baz, "baz"); //-> true

extend(obj, { foo: "foooooo" });
assert.equal("" + obj.foo, "foooooo"); //-> true
assert.equal(obj.foo.baz, "baz"); //-> true

您需要创建一个新的字符串对象,并将任何新属性和值扩展到该字符串对象。下面我提供了一个简单的例子。也就是说,可以修改此示例以满足您的目的(您需要创建一个自定义的extend或setter函数)

属性设置器函数的示例 更新对象
你不能。字符串是不可变的,无论您如何“构造”它们(文字或对象)

您应该做的只是使用一个实际对象来保存您的值和字符串

在最基本的层面上,这将是:

var obj = {
  foo: "bar"
};

// later...
obj.baz = "baz";
"" + obj.foo; //-> "bar";

你也可以考虑使用一元类型作为一个“放大器”/装饰器,但是对于这个用例来说,这似乎是多余的。



另外,向字符串对象添加属性和“随机”函数不是一个好的OOP选择。它们与字符串的值严格无关,仅对更高级别的对象才有意义,它们应该位于更高级别的对象中。

我建议您为此使用自定义类型,而不是默认的字符串类型。ES6规范定义字符串对象的基础值存储在其“[[StringData]]内部插槽”中。此插槽的唯一分配位置是通过
新字符串
构造函数,因此它是隐式不变的。您可以创建一个新类型,该类型具有所需的类似字符串的行为,同时是可变的

class MutableString {
  constructor(value) {
    this.value = value;
  }

  toString() {
    return this.value;
  }
}

var obj = {
  foo: new MutableString('bar')
};
obj.foo.baz = "baz";


console.assert("" + obj.foo == "bar");
console.assert(obj.foo + "" == "bar");
console.assert(obj.foo.baz == "baz");
console.assert(Object.keys({[obj.foo]: 1})[0] == "bar");

obj.foo.value = "foooooo";
console.assert("" + obj.foo == "foooooo");
console.assert(obj.foo + "" == "foooooo");
console.assert(obj.foo.baz == "baz");
console.assert(Object.keys({[obj.foo]: 1})[0] == "foooooo");
因为这不是一个真正的字符串,它不支持任何字符串方法,所以它可能不适合您使用。但是它更灵活,更清晰,所以我建议如果可能的话考虑一下


可能需要定义一个
valueOf()
方法,比如
toString()
来处理其他一些情况,但我还没有验证。

可能重复的@Ben-string原语和string对象是两件不同的事情。对象是完全可变的,我需要这种可变性
obj.foo.stringValue=“baz”
assert.equal(obj.foo.stringValue,“foo”)
。据我所知,字符串值是不可变的,尽管您可以向字符串对象添加其他属性。挑战是您需要保留
String
对象,因为它可能有自己的原型方法。我没有花太多的时间在一个解决方案上,但是请考虑我所引用的内容,ES6规范定义了一个字符串对象的基础值存储在它的[[ [ String DATAB] ]内部插槽中。这个槽的唯一分配位置是通过
new String()
构造函数,因此它是隐式不可变的,尽管我不确定它是否被显式描述为这样。String对象确实是可变的。打开控制台:
var foo=newstring(“foo”);foo.bar=“bar”;控制台日志(foo.bar)感谢您的架构补遗。不幸的是,我正在以
foo.bar=foo-bar
foo.bar.baz=foo-bar-baz
的形式处理客户机数据。该数据位于一个以换行符分隔的文本文件中,我需要将其转换为JS对象,以便在代码中使用。我无法更改源文件。fml@RyanWheale-您需要将其转换为在谁的代码中使用?您的或客户的?@RyanWheale和关于是否可变,字符串对象是首要的对象,因此是可扩展的,但您不能改变内部值。我想说这个实例是可变的(就像你做的那样)更准确一些,但是如果不解释什么是可以变异的细节,那就相当误导人了。谢谢。我刚刚发现了字符串对象,并且在构造过程中创建的数据确实是不可变的。谢谢你提供的信息。谢谢你为此付出的所有努力。不幸的是,字符串对象更像数组——每个字母都是一个索引,并且有一个长度属性。所以你的函数会复制旧的字母。但你把我引向了正确的方向。有趣的是,构造的字符串对象是不可变的:
var foo=new String(“foo”);foo[0]=“b”;foo.toString();//->“福”@RyanWheale我可能误解了你的问题;是字符串值是不可变的,您将无法修改/更改它。你要什么?在这些操作结束时,
obj.foo
将从
String('bar')
更改为
String('foot')
,并保留应用于
String('bar')
的任何新的/附加属性。我想这就是你所要求的。不,你是正确的——你似乎是唯一理解这个问题的人。函数在以下方面失败:
createNewString(新字符串(“foot”)、新字符串(“bar”);//->“bart”
@RyanWheale请尝试此更新,但请注意,这是一个简单的示例,不一定是一个涵盖所有边缘情况的健壮解决方案。还有更好的实现技术,与本示例相比,您可能更喜欢这些技术,或者可能会有性能优势。不用说,你应该根据自己的情况进行调整。谢谢,这非常有用。我希望得到一些不需要自己上课的东西。将String.prototype复制到这个上很简单-只需将String.prototype.fn.apply每个应用到this.value。我一定会把这个放在我的后口袋里。
obj.foo = createNewString( obj.foo, 'foot' );
//obj.foo=='foot' and obj.foo.baz=='baz'
var obj = {
  foo: "bar"
};

// later...
obj.baz = "baz";
"" + obj.foo; //-> "bar";
class MutableString {
  constructor(value) {
    this.value = value;
  }

  toString() {
    return this.value;
  }
}

var obj = {
  foo: new MutableString('bar')
};
obj.foo.baz = "baz";


console.assert("" + obj.foo == "bar");
console.assert(obj.foo + "" == "bar");
console.assert(obj.foo.baz == "baz");
console.assert(Object.keys({[obj.foo]: 1})[0] == "bar");

obj.foo.value = "foooooo";
console.assert("" + obj.foo == "foooooo");
console.assert(obj.foo + "" == "foooooo");
console.assert(obj.foo.baz == "baz");
console.assert(Object.keys({[obj.foo]: 1})[0] == "foooooo");