This question already has answers here:
How is a Javascript string not an object?
(2 answers)
Closed 7 years ago.
Here are two reasons to think strings are objects. First, you can create a string in the following way:
var mystring = new String("asdf");
I'm under the impression that the constructor function following the new operator has to return an object. Second, strings seem to have properties and methods. For example:
mystring.toUpperCase();
BUT, if strings were objects, then we'd expect something like the following to work:
function string_constructor() {
return "asdf";
}
var mystring = new string_constructor();
But it doesn't, and I've been told it doesn't because strings aren't objects. So are strings objects or not? And, either way, how can I make sense of everything I've listed?
Speaking about language types, Strings are values of the String type.
The language has five primitive types, which are String, Number, Boolean, Null and Undefined.
There are String objects (also for Number or Boolean), they are called primitive wrappers, they are created when you use the constructor function associated with them, for example:
typeof new String('foo'); // "object"
typeof 'foo'; // "string"
But don't get confused with them, you will rarely need to use primitive wrappers, because even if primitive values are not objects, you can still access their inherited properties, for example, on a string, you can access all members of String.prototype, e.g.:
'foo'.indexOf('o'); // 2
That's because the property accessor (the dot in this case) temporarily converts the primitive value to an object, for being able to resolve the indexOf property up in the prototype chain.
About the constructor function you have in your question, as you know, it won't return the string.
Functions called with the new operator return an implicit value, which is a new object that inherits from that function's prototype, for example:
function Test () {
// don't return anything (equivalent to returning undefined)
}
new Test() instanceof Test; // true, an object
If an object is returned from the constructor, that newly created object (this within the constructor) will be lost, so the explicit returned object will come out the function:
function Test2() {
return {foo: 'bar'};
}
new Test2().foo; // 'bar'
But in the case of primitive values, they are just ignored, and the new object from the constructor is implicitly returned (for more details check the [[Construct]] internal operation, (see step 9 and 10)).
In JavaScript, strings come in two flavors:
There is a String language type which contains values like "foo" and 'bar'. Those values are primitive values. Read about the String type here
Then there is a String constructor. (A constructor is a function object which is used to create new instances of a certain "class" (or pseudo-class)). So this: new String("foo")
will create a new object (a value of the type Object), which contains the primitive value "foo". Read about the String constructor here
In practice you don't use the new String('foo') notation, but the string literal notation 'foo'.
So to answer your question:
In JavaScript, strings are not objects. They are primitive values. However, there exist String objects which can be used to store string values, but those String objects are not used in practice.
Primitive strings behaves like objects in JavaScript because they are automatically converted to objects when you call an object method:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String
String objects may be created by
calling the constructor new String().
The String object wraps JavaScript's
string primitive data type with the
methods described below. The global
function String() can also be called
without new in front to create a
primitive string. String literals in
JavaScript are primitive strings.
Because JavaScript automatically
converts between string primitives and
String objects, you can call any of
the methods of the String object on a
string primitive. JavaScript
automatically converts the string
primitive to a temporary String
object, calls the method, then
discards the temporary String object.
For example, you can use the
String.length property on a string
primitive created from a string
literal
String are both primitive and object type. Think about int, float, char ... which have real Object classes like Integer, Float and Char in Java.
String is a wrapper around the primitive string datatype. When you do something like var s = "My String" then a String wrapper object is created behind the scenes when needed..
It is interesting however that typeof s = 'string' instead of 'object'. Anybody know why that is?
Strings are objects, but what you are doing in your example is not creating a new String. By using 'new' you are creating an instance of a Object, not a 'string'
var F = function() {
return 'c';
};
var a = new String('a');
var b = 'b';
var c = new F();
alert("a is: " + typeof a + ", b is: " + typeof b + ", c is: " + typeof c);
// alerts: a is: object, b is: string. c is: object
You shouldn't use 'new' for strings regardless (or arrays, or 'simple' objects.)
Related
This question already has answers here:
What is the difference between string primitives and String objects in JavaScript?
(12 answers)
Closed 2 years ago.
I have an argument to a method that I need to make sure is a string. Using var instanceof String was failing, so I did a console.log(var.constructor.name, var instanceof String and got this output:
String false
Why does JavaScript consider the constructor's name to be 'String' but doesn't consider the variable to be an instance of String?
instanceof attempts to find the constructor (the right hand operand) prototype (as in the prototype property) in the object (the left hand operand) prototype chain. If the left hand operator is not an object then it wasn't really instanced by any constructor, so any left hand operator that is not an object would return false.
Now, if var (which isn't a valid identifier) is truly a primitive string then doing var.constructor.name would use an intermediate value that is a String object (usually referred as autoboxing). That would be an instance of String.
However there's no "autoboxing" when using instanceof. Therefore never an object. Therefore not an instance of any constructor.
String is a primitive so you check the type by using typeof keyword.
console.log(typeof 'some string')
You can use it as:
if (typeof variable === 'string') {
// the `variable` is definitely a string.
}
String is a class/object in Javascript. So new String('hello') returns an object which is an instanceof String.
let x = 'hello'
typeof x === 'string' // returns true
x instanceof String // returns false
x.constructor.name // returns 'String'
let y = new String('a')
typeof y === 'string' // returns false
y instanceof String // returns true
y.constructor.name // returns 'String'
Here is what is said on String object - MDN, with emphasis added
String literals (denoted by double or single quotes) and strings returned from String calls in a non-constructor context (that is, called without using the new keyword) are primitive strings. JavaScript automatically converts primitives to String objects, so that it's possible to use String object methods for primitive strings. In contexts where a method is to be invoked on a primitive string or a property lookup occurs, JavaScript will automatically wrap the string primitive and call the method or perform the property lookup.
We all know Strings somewhat behaves like an Array.You can even apply some of the array methods to it and take benefits, like the below example.
[].filter.call('abcdef',function(val){
return val<'e';
});
Also,
var a='xyz';
I can access first element using a[0] or I can call a.length like an Array
My question is why String behaves like an Array. and if it does, why do I get false below when I check if it is an instance of Array. Is String Array-like?
'a' instanceof Array
All that Array.prototype.filter really requires is that the variable being iterated over has a length property, and that the variable has numeric-indexed values. See (part of) the polyfill:
var len = this.length >>> 0,
res = new Array(len), // preallocate array
t = this, c = 0, i = -1;
if (thisArg === undefined){
while (++i !== len){
// checks to see if the key was set
if (i in this){
if (func(t[i], i, t)){
res[c++] = t[i];
}
}
}
}
Strings fulfill this condition - strings have a length property, and numeric indicies accessed on the string resolve to individual characters.
But you can do the same thing with arbitrary objects:
const obj = {
0: 'foo',
1: 'bar',
length: 2
};
const result = [].filter.call(obj, val => val.startsWith('f'));
console.log(result);
You could say that obj is array-like as well, since it has a length property and numeric indicies. Most array methods like .filter, .reduce, etc can be .called on array-like objects, even if those objects aren't actual arrays.
(Technically, you can also call array methods on non-array-like objects too, it just won't do anything useful - no iterations may be performed)
To use instanceof you need to create an instance of an Object and a is not an instance of one. It is a primitive or also known as string literal:
String literals (denoted by double or single quotes) and strings
returned from String calls in a non-constructor context (i.e., without
using the new keyword) are primitive strings. JavaScript automatically
converts primitives to String objects, so that it's possible to use
String object methods for primitive strings. In contexts where a
method is to be invoked on a primitive string or a property lookup
occurs, JavaScript will automatically wrap the string primitive and
call the method or perform the property lookup.
For example:
let foo = 'abc' // primitive
let boo = new String() // object
console.log(foo instanceof String) // false
console.log(boo instanceof String) // true
console.log(typeof foo) // 'string' <-- notice not String
console.log(typeof boo) // object
This is simply due to:
The instanceof operator tests the presence of constructor.prototype in
object's prototype chain
But as we explained above we are dealing with string literals which are created without a constructor call (new keyword) and only boxed for our convenience when operating on them. They are not actual instances of String and thus instanceof returns false.
The reason you can use Array.filter on the string primitive is simply due to the fact that it was boxed for you to a String from where it got the length property at the time of execution.
For example in the case of V8 engine string primitive is parsed/boxed to String and a String to a StringObject. Notice they are actually different instances.
Array.filter only cares about that length property and numeric indicies as pointed nicely by CertainPerformance which are provided by the boxing to String. Example:
console.log(Object.getOwnPropertyNames('a')) // ["0", "length"]
However String is not StringObject and thus instanceof would return false.
As per MDN the in operator returns true if the property exists and accordingly the first example logs true. But when using a string literal, why is it throwing an error instead of logging false?
let let1 = new String('test');
console.log(let1.length);
console.log('length' in let1)
var let1 = 'test';
console.log(let1.length);
console.log('length' in let1);
In a sense it is a matter of timing. String literals do not have any properties. The reason that you can call methods and lookup properties on primitive strings is because JavaScript automatically wraps the string primitive in a String object when a method call or property lookup is attempted. JavaScript does not interpret the in operator as a method call or property lookup so it does not wrap the primitive in an object and you get an error (because a string primitive is not an object).
See Distinction between string primitives and String objects
Also, the same docs referenced in your question specifically note that using in on a string primitive will throw an error.
You must specify an object on the right side of the in operator. For
example, you can specify a string created with the String constructor,
but you cannot specify a string literal.
It throws an error because in is an operator for objects:
prop in object
but when you declare a string as `` (` string(template) literals) or "" '' (",' string literals) you don't create an object.
Check
typeof new String("x") ("object")
and
typeof `x` ("string").
Those are two different things in JavaScript.
JavaScript operator in only applicable to an Objects instances.
When you using constructor new String('abc') this will causing creating of a String object instance.
In other side, when you using only string literals or call function String('abc') without new it creates an string primitive. (like Number and Boolen)
Some behaviour of primitives and objects is differrent, look at this simple example's output:
console.log(typeof (new String('ddd'))) // "object"
console.log(typeof ('ddd')) // "string"
console.log(eval('1 + 2')) // 3
console.log(eval(new String('1 + 2'))) // {"0":"1","1":" ","2":"+","3":" ","4":"2"}
In code where you use methods on string primitives javascript engine automatically wraps primitives with corresponding objects to perform methods call.
But in it is not an method call, its language operator an in this case wrapping is not applied.
PS: Sorry for my english.
typeof('test') == string (string literal)
typof(new String('test')) == object (string object)
you can't use in with a string literal.
The in operator returns true if the specified property is in the specified object or its prototype chain.
The in operator can only be used to check if a property is in an
object. You can't search in strings, or in numbers, or other primitive
types.
The first example works and prints 'true' because length is a property of a string object.
The second example doesn't work and gives you an error because you are trying to look for a property length in something (a string) that is not an object.
Watching a tutorial today I came across the following:
var q2Var1 = "hi there.",
q2Var2 = String( "another string here." );
Is q2Var the "constructor notation" and q2Var the "literal notation" for declaring a variable, or am I not drawing the correct conclusion?
Thank you.
No, neither of those use a constructor to create a string object.
The first is just a string primitive, the second is a string primitive that is sent through the String conversion function, which will just return the string primitive unchanged.
The String conversion function is usually used to turn other things into string primitives, for example a number:
var s = String(42);
To create a String object you use the new keyword:
var s = new String("hi there.");
The String object has all the methods that you are used to use on a string, like the length property. The reason that you can use them on string primitives also, is that they are automatically converted to String objects when you use a method on them.
So, this:
var l = "asdf".length;
actually does the same as:
var l = new String("asdf").length;
The String conversion function always returns a string primitive, so if you have a String object, the function will turn it back into a string primitive:
var s = "asdf"; // typeof s returns "string"
var s = new String(s); // typeof s now returns "object"
s = String(s); // typeof s now returns "string"
I never heard those names before, but 'constructor notation' would most likely be the q2Var2 one, since you're passing arguments to the constructor of String. It's not really important how you call them though, is it? :P
Is Object the base class of all objects in Javascript, just like other language such as Java & C#?
I tried below code in Firefox with Firebug installed.
var t = new Object();
var s1 = new String('str');
var s2 = 'str';
console.log(typeof t);
console.log(typeof s1);
console.log(typeof s2);
The console output is
object
object
string
So, s1 and s2 are of diffeent type?
Yes, 'str' is a string literal, not a string object.
A string literal has access to all of a string's objects and methods because javascript will temporarily cast a string literal as a string object in order to run the desired method.
Finally:
Where the two differ is their treatment of new properties and methods. Like all Javascript Objects you can assign properties and methods to any String object. You can not add properties or methods to a string literal. They are ignored by the interpreter.
Read up more here.
The process is called boxing/unboxing.
This means that whenever the interpreter/compiler sees a primitive type used as an Object then it will use
new Object([primitive])
to get a valid instance. And in the same way, as soon as you try to use it as a primitive (as in an expression) it will use
[boxedobject].valueOf()
to get the primitive.
In ECMAScript (javascript) the constructor of Object is able to box all primitives.
Read this: http://skypoetsworld.blogspot.com/2007/11/javascript-string-primitive-or-object.html
and this: https://developer.mozilla.org/en/JavaScript/Glossary#primitive
and this: https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/String