JavaScript中使用new String("x")有什么作用?

46

使用 new String("already a string") 的用例是什么?

它的整个意义是什么?

9个回答

63

new String("foo")创建的String对象实际上用处非常有限,它与原始字符串值唯一的区别在于作为一个对象,它可以存储属性:

var str = "foo";
str.prop = "bar";
alert(str.prop); // undefined

var str = new String("foo");
str.prop = "bar";
alert(str.prop); // "bar"

如果您不确定可以传递给您的代码哪些值,那么我建议您的项目存在更大的问题。没有任何一个原生的JavaScript对象、主要库或DOM方法会返回一个String对象而不是字符串值。但是,如果您想要确保您拥有一个字符串值而不是String对象,您可以按照以下方式进行转换:

var str = new String("foo");
str = "" + str;

如果你要检查的值可能是任何对象,则你有以下几个选项:

  1. 不必担心String对象,只需使用typeof。这是我的建议。

    typeof str == "string"

  2. 同时使用instanceof和typeof。这通常可以工作,但缺点是对于在另一个窗口中创建的String对象会返回false negative。

    typeof str == "string" || str instanceof String

  3. 使用鸭子类型。检查一个或多个特定于字符串的方法的存在,例如substring()或toLowerCase()。这显然不太精确,因为它会针对具有您正在检查的名称的方法的对象返回false positive,但在大多数情况下,它已经足够了。

    typeof str == "string" || typeof str.substring == "function"


1
我正在创建一个类,在其构造函数中接受一个参数。但是,这个参数是由用户提供的。如果参数是字符串,构造函数将执行某些操作,否则将执行其他操作。因此,我想知道有没有办法确定参数是否是字符串(由用户提供)。我不能使用str = "" + str,因为我不能假定参数只能是“true”字符串或字符串对象..它可能是其他对象。 - Pacerier
2
第一句话就把一切都说清楚了。 - rhigdon
3
str = "" + str;任何类型都转化为字符串。如果你只希望把 String 对象转换为字符串 (Number 对象转换为数值等),而不改变其他东西,可以写成str = str.valueOf() - Timwi
你可以通过Object.prototype.toString.call(value)来检查一个值是否为字符串,它在原始值和对象的情况下都会返回"[object String]"。与instanceof不同,即使对象是在不同的窗口中创建的,这种方法也能正常工作。但是我的建议是永远不要使用对象包装器,因为它们绝对没有合法的使用场景。 - undefined
尝试{"".valueOf.call(value);var isString = true}catch(e){isString = false}也能无误地告诉你一个值是否为字符串。适用于原始值和对象。 - undefined
显示剩余2条评论

24

Javascript的创建者为像字符串或整数这样的基本类型创建了包装器,只是为了使它类似于Java。不幸的是,如果有人使用new String("x")创建一个新字符串,元素的类型将是"object"而不是"string"。

var j = new String("x");
j === "x"  //false
j == "x" //true

2
我真的很喜欢这个答案。 - Tek

10

String对象可以拥有属性,而字符串原始值则不行:

var aStringObject=new String("I'm a String object");
var aStringPrimitive="I'm a string primitive";

aStringObject.foo="bar";
console.log(aStringObject.foo); //--> bar

aStringPrimitive.foo="bar";
console.log(aStringPrimitive.foo); //--> undefined

String 对象可以被继承,而字符串原始值则无法:

var foo=Object.create(aStringObject);
var bar=Object.create(aStringPrimitive); //--> throws a TypeError

String对象只能与其自身相等,而不能与具有相同值的其他String对象相等,而具有相同值的原始类型被认为是相等的:

var aStringObject=new String("I'm a String object");
var anotherStringObject=new String("I'm a String object");

console.log(aStringObject==anotherStringObject); //--> false

var aStringPrimitive="I'm a string primitive";
var anotherStringPrimitive="I'm a string primitive";

console.log(aStringPrimitive==anotherStringPrimitive); //--> true

您可以实现类似于重载的行为:

function overloadedLikeFunction(anArgument){
    if(anArgument instanceof String){
        //do something with a String object
    }
    else if(typeof anArgument=="string"){
        //do something with a string primitive
    }
}

或者指定参数用途:
function aConstructorWithOptionalArugments(){
    this.stringObjectProperty=new String("Default stringObjectProperty value");
    this.stringPrimitiveProperty="Default stringPrimitiveProperty value";
    for(var argument==0;argument<arguments.length;argument++){
        if(arguments[argument] instanceof String)
            this.stringObjectProperty=arguments[argument];
        if(typeof arguments[argument]=="string")
            this.stringPrimitiveProperty=arguments[argument];
    }
}

或跟踪对象:

var defaultStringValue=new String("default value");
var stringValue=defaultStringValue;

var input=document.getElementById("textinput") //assumes there is an text <input> element with id equal to "textinput"
input.value=defaultStringValue;
input.onkeypress=function(){
    stringValue=new String(this.value);
}

function hasInputValueChanged(){
    //Returns true even if the user has entered "default value" in the <input>
    return stringValue!=defaultStringValue;
}

存在String对象和字符串原始值在Javascript中实际上给了你两种不同的字符串"类型",它们有不同的行为和用法。对于BooleanNumber对象及其相应的原始值也是如此。
然而,在使用函数方法bind()call()apply()时,要注意不要将字符串(或其他)原始值作为this的值传递,因为该值将在使用之前被转换为String对象(或一个BooleanNumber对象,具体取决于原始值)。请谨慎使用。
function logTypeofThis(){
    console.log(typeof this);
}

var aStringPrimitive="I'm a string primitive";
var alsoLogTypeofThis=logTypeofThis.bind(aStringPrimitive);

console.log(typeof aStringPrimitive); //--> string;
logTypeofThis.call(aStringPrimitive); //--> object;
logTypeofThis.apply(aStringPrimitive); //--> object;
alsoLogTypeofThis(); //--> object;

还有意外/反直觉的返回类型:

var aStringObject=new String("I'm a String object");
console.log(typeof aStringObject); //--> object
aStringObject=aStringObject.toUpperCase();
console.log(typeof aStringObject); //--> string

3

如果你真的想要非常谨慎,你可以使用 instanceof

if(typeof x === "string" || x instanceof String)
instanceof 运算符也可以正确地处理 String 的子类:

obj instanceof ConstructorFunction 的工作原理是检查 ConstructorFunction.prototype 是否在 obj 的原型链中。

我认为我从未在 JavaScript 中使用过 String 类,但是追求正确性并保持警惕是没有错的。

1
在大多数情况下,你是独自工作并可以控制自己,或者在团队中有团队指南,或者可以看到你正在处理的代码,所以这不应该是一个问题。但你总是可以采取额外的安全措施:
var obj = new String("something");
typeof obj; // "object"

obj = ""+obj;
typeof obj; // "string"

更新

虽然这似乎有效,但我还没有考虑过它的影响:

var obj = new String("something"), obj2 = "something else";
obj.constructor === String; // true
obj2.constructor === String; // true

当然,您应该检查对象是否具有构造函数(即它是否是一个对象)。
因此,您可以编写以下代码:
isString(obj) {
   return typeof obj === "string" || typeof obj === "object" && obj.constructor === String;
}

虽然我建议您只使用 typeof 和 "string",但用户应该知道通过普通字符串字面量传递。

我应该注意到,这种方法可能容易受到某人创建对象并将其构造函数设置为 String(尽管它不是字符串...)的影响。


那么,检查变量是否为字符串的最佳方法是什么? - Pacerier
仅仅检查constructor属性是不够的。在JavaScript中,可能会有一些奇怪的人子类化String。 - mu is too short
@mu太短了,是的你说得对,虽然我考虑过instanceof,但看起来OP只是想区分对象、字符串字面量和new String('blah')。无论如何,这个想法已经出现了,我们可以整天吹毛求疵。 - davin
我认为,如果你要追求严谨,那就要做到底。不要半途而废 :) - mu is too short

0
Object.prototype.toString.call(aVariable) == '[object String]'

0

你也可以使用 toString 方法将一个 String 对象(以及其他任何对象)转换为 String 原始值:

var str = new String("foo"); typeof str; // object typeof str.toString(); // string

0

感谢大家,即使经过这么多年,这个问题仍然没有一个确切的答案。

JavaScript 有两种类型的数据,

  1. 原始值:- 字符串(let a = 'testStr')、数字、布尔、null、undefined、Symbol 和 BigInt。
  2. 对象:- 其他所有内容(函数、数组、JS 对象等)

JS 设计时考虑到效率(你知道在 V8 上的JS就像火箭一样),所有原始值都是不可变的(更改 str 或 num 会在幕后创建一个新变量),而对象是可变的。

为了支持像对象一样使用原始值,JS 有了自动装箱的特性。因此,当我们使用任何方法(例如对于数字的 toString())与原始值一起使用时,JS 会自动将其转换为相应的对象,然后执行该方法并将其转换回原始值。通常情况下,我们不应该使用构造函数(带new)来代替原始值,而应该像使用原始值一样使用它(例如 let str = 'testStr')。使用构造函数对象而不是原始值可能会导致执行缓慢和复杂化。


-1

为什么需要检查它是否为字符串?

只需检查它是否已定义或为空,否则可以进行防御性转换为您想要的任何类型,无论是 var bar = new String(foo); 还是 var bar = "" + foo;


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接