Difference in these 2 Strings (JavaScript) - javascript

I was trying to create string data-types variables with values in 2 ways.
As string-literal
Using New Keyword
But to me it seems that these both are different in representation on console.log.
Can someone tell me if 2nd way doesn't return string or is it someway different?
var str1 = "abc";
var str2 = new String("def");
console.log(str1);
console.log(str2);
Expected:
abc, def
Output:

JavaScript has two main type categories, primivites and objects.
typeof new String(); // "object"
typeof ''; // "string"
For statements of assigning primitive values to a variable like:
var str1 = "Hi";
JavaScript will internally create the variable using:
String("Hi")
Using the new keyword works differently and returns an object instead.

Calling new String(something) makes a String instance object.
The results look the same via console.log() because it'll just extract the primitive string from the String instance you pass to it.
So: just plain String() returns a string primitive. new String('xyz') returns an object constructed by the String constructor.
It's rarely necessary to explicitly construct a String instance.

You are working with two different things.
The var str1 = "abc" gives you a primitive.
While the var str2 = new String("def"); gives you a string object.
These two types behave differently

The String object lets you work with a series of characters; it wraps Javascript's string primitive data type with a number of helper methods.
As JavaScript automatically converts between string primitives and String objects, you can call any of the helper methods of the String object on a string primitive.

When you print an object, often the console print the object's properties.
If is a primitive the console just print the value.
The primitive is not boxed, but if you create a string with a constructor the string is boxed in the object and always have properties.
If is just a literal, it only have properties when you access to a string's property with . operator because boxing occurs, but after that, it still being a literal with nothing additional added, because of that when you print "The cat is very grumpy", just print the value and nothing more. primitives literals are not always objects with properties, are only objects when are boxed.

Related

If a String is immutable in JavaScript why does the following code mutate a string?

I have read the input as a string and, after splitting it, the string becomes an object.
process.stdin.resume();
process.stdin.setEncoding('utf8');
process.stdin.on('data',(c)=>{
in += c;
});
process.stdin.on('end',()=>{
spliter(in);
});
function spliter(in){
console.log(typeof(in));
in = in.split('\n');
console.log(typeof(in));
}
Your code does not mutate the string.
Strings (along with the other primitive types) are immutable in JS.
Mutating something means that changing it without creating another one.
String modifier methods return a new string, but doesn't change the original, for example:
const a = 'Hello world!'
const b = a.slice(0,5)
console.log(a) //Hello world!
console.log(b) //Hello
However, you can still reassign a string variable with a new string (but that's not mutation):
let a = 'Hello world!'
a = a.slice(0,5)
console.log(a) //Hello
Your code is a bit more complicated. String#split() returns an array of strings, but doesn't mutate the original:
const a = 'Hello world!'
const b = a.split('o')
console.log(a) //Hello world!
console.log(b) //['Hell', ' w', 'rld!']
Arrays are (in fact) objects, and they are mutable, but not the strings (and other primitives) they contain.
As others have pointed out, in the example provided, the string primitive is not being mutated.
The variable is being re-assigned to the value returned by the split() method, which is being called on a String wrapper object, which is automatically used when calling a method on a string. ​
let myString = 'Hello World!';
console.log("BEFORE reassignment - variable type is: " + typeof(myString)); // string
myString = myString.split(' '); // <----- method called on String object wrapper, returns an array, which is re-assigned to the myString variable
console.log(myString); // ['Hello', 'World!']
console.log("AFTER reassignment - variable type is: " + typeof(myString)); // object
Below is some further context:
The set of types in the JavaScript language consists of primitive values and objects.
Source: MDN Web Docs
A string is a primitive value.
In JavaScript, all primitive types are immutable and have no methods, however:
​
It is important not to confuse a primitive itself with a variable assigned a primitive value. The variable may be reassigned a new value, but the existing value can not be changed in the ways that objects, arrays, and functions can be altered.
Source: MDN Web Docs
Even though primitive types have no methods, it is possible to call a method on a primitive because all primitive values, except for null and undefined, have object equivalents that wrap around the primitive values:
String for the string primitive.
Number for the number primitive.
BigInt for the bigint primitive.
Boolean for the boolean primitive.
Symbol for the symbol primitive.
Source: MDN Web Docs
When you call a String instance method on a string primitive the following occurs:
The primitive value is temporarily converted into an object
The object's method property is used
(e.g slice() will return a new string and split() will return an array of strings)
The object is converted back to a primitive
Sources:
Head First JavaScript Programming (2014), page 306.
JavaScript Programmer's Reference (2010), page 157.
When you modify a string variable, javascript doesn't actually modify the string that's in memory, it instead creates a brand new string that looks like a modification of the initial string:
let str = " hi ";
str = str.trim(); // a new string "hi" is created
console.log(str);
That is all javascript means by saying its strings are immutable. If you want to prevent a string variable from being changed, you can use const:
const str = "Can't change me";
str = "Want to bet?" // throws error.
Quite simply, you are NOT mutating the string
If you were, the following code (based on your code) would output Object in both console.log's
let x = 'this is a string';
function spliter(x){
x = x.split('\n');
console.log(typeof(x));
}
spliter(x);
console.log(typeof(x));

Can we say that String is an object in Javascript?

I'm always confused when I hear strings are primitives in JS, because everybody knows that string has different methods like: length, indexOf, search etc.
let string = "Please locate where 'locate' occurs!";
let pos = str.lastIndexOf("locate");
let position = str.search("locate");
It's true that everything in JavaScript is just like object because we can call methods on it. When we use new keyword with string it becomes an object otherwise it's primitive type.
console.log(typeof new String('str')); //object
console.log(typeof 'str'); //string
Now whenever we try to access any property of the string it box the the primitive value with new String()
'str'.indexOf('s')
is equivalent to
(new String(str)).indexOf('s').
The above process is called as "Boxing". "Boxing" is wrapping an object around a primitive value.
Strings are not objects, they are native types, like numbers, but if you want to access the method on it they are boxed with String object. The same happen with numbers you can call (10).toString() but in fact you're calling toString on Number instance that wraps 10, when you call the method.
Not certainly in that way.
If you try to use a class method for a primitive, the primitive will be temporarily wrapped in an object of the corresponding class ("boxing") and the operation will be performed on this object.
For example,
1..a = 2;
It's equal to:
num = new Object(1.);
num.a = 2;
delete num;
So, after executing the operation, the wrapper will be destroyed.
However, the primitive itself will remain unchanged:
console.log( 1..a ) // undefined
Every data type is a object in JavaScript.
String, array, null, undefined . Everything is a object in JavaScript

Creating Numbers and Strings with Object()

I would love a clear explanation as to better understand what's going on here?
I can create what look like primitive types with Object. It looks like a number but not quite for a string. I was under the impression that Object() was used to create all objects in js (ie of type object) but not primitive types, like number, string boolean.
There are times when a primitive type (Boolean, Number or String) needs to be converted to object albeit temporarily.
Look at this example:
var str = 'javascript';
str = str.substring(4);// You get "script" but how?
How can you call a function on something that is not an object? The reason is that primitive value is wrapped into Object(String) on which substring() method is defined. If it was not done, you would not be able to call the method in the primitive type. Such wrappers are called Primitive Wrappers.
Also, it doesn't mean that str has now become an object. So, if you said:
str.myProp = 10;
and then console.log(str.myProp);//You would get undefined
The difference between a reference type and a primitive wrapper object is lifetime. Primitive wrappers die soon.
So you can think of
var str = 'javascript';
str = str.substring(4);// You get "script" but how?
As these lines:
var str = new String(“javascript”);
str = str.substring(4);
str = null;
Now coming to what you are doing:
number = Object(5);
Here you are wrapping a number primitive into an object. It is as if you had written:
number = new Number(5);
Here, Object(5) is behaving as a factory and depending on the type of the input(number, string), it gives back object by wrapping primitive value into it.
So, Object(5) is equivalent to new Number(5) and Object('test') is as if saying new String('test').
Hope this helps!
The notion of primitives and objects is slightly implementation dependent. But you can think of it like this:
Primitives are not objects. They have their own special semantics, such as the string "hello" is the same no matter how many times you create one. However, the object new String("hello") should return a new string every time.
In many implementations, there is auto-boxing and unboxing of primitives when they need to act like objects and vice-versa. I would suggest reading this question for more details: What is the difference between string literals and String objects in JavaScript?
You can use Object.prototype.valueOf() to get [[PrimitiveValue]] 5 or "test".
var number = new Object(5);
var aString = new Object("test");
console.log(number.valueOf(), aString.valueOf());
5.toString();
As you can see Number is an object. But number is not. In some cases primitives are wrapped by objects to implement object like behaviours...
5 // primitive type
Object(5) // wrapper of that primitive type
5.toString() === Object(5).toString() //...

Is there any use value to using the toString method on a string?

I can't figure out how the toString method could possibly be of any use when used on a string. A string is already a string and by its very nature it returns the value of the string.
This...
console.log("Hello"); // => "Hello"
console.log(typeof "Hello"); // => string
Seems exactly the same as this...
console.log("Hello".toString()); // => "Hello"
console.log(typeof "Hello".toString()); // => string
If toString converts something to a string and returns it's value as a string and a string is a string and returns the value of a string I can only conclude that this method is totally meaningless. Am I missing something?
Note: "What is the difference between string literals and String objects in JavaScript?" and "Is there any use value to using the toString method on a string?" are clearly not the same question so I don't think this should be considered a duplicate.
There might be a misunderstanding.
Strings are primitive values, that is, they are not object. And thus they don't have methods.
However, some primitive values can be wrapped in analogous objects. it's the case of booleans, numbers and strings.
When you attempt to use one of these primitive values as an object, e.g. calling a method, the following happens under the hood:
An object wrapper (in this case, a string object) is created
The property is read/written in that object
No reference to that object is stored anywhere, and thus it's usually garbage collected
Therefore, yes, using toString method on a string primitive is usually useless, because it only converts it to an object string under the hood, and the method converts the string object back to a string primitive.
However, that's not the case when you have a string object, because you may want to convert it to a string primitive:
var obj = new String('hello');
typeof obj; // 'object'
var str = obj.toString();
typeof str; // 'string'
A case in which toString used on a string primitive is when you have replaced it with a custom function (not recommended):
String.prototype.toString = function() { return '[' + this + ']' };
'hello'.toString(); // "[hello]"
String object and String literal are two different things. Read more about it here:
What is the difference between string literals and String objects in JavaScript?

adding properties to primitive data types other than Array

I'm not supposed to add elements to an array like this:
var b = [];
b.val_1 = "a";
b.val_2 = "b";
b.val_3 = "c";
I can't use native array methods and why not just an object. I'm just adding properties to the array, not elements. I suppose this makes them parallel to the length property. Though trying to reset length (b.length = "a string") gets Uncaught RangeError: Invalid array length.
In any case, I can still see the properties I've set like this:
console.log(b); //[val_1: "a", val_2: "b", val_3: "c"]
I can access it using the dot syntax:
console.log(b.val_1); //a
If an array is just an object in the same way a string or a number is an object, why can't (not that I'd want to) I attach properties to them with this syntax:
var num = 1;
num.prop_1 = "a string";
console.log(num); //1
I cannot access its properties using dot syntax
console.log(num.prp); //undefined
Why can this be done with array and not with other datatypes. For all cases, I should use {} and would only ever need to use {}, so why have arrays got this ability?
JSBIN
Because arrays are treated as Objects by the language, you can see this by typing the following line of code:
console.log(typeof []) // object
But other types like number literals, string literals NaN ... etc are primitive types and are only wrapped in their object reprsentation in certain contexts defined by the language.
If you want to add properties or methods to a number like that, then you can use the Number constructor like this:
var num = new Number(1);
num.prop_1 = "fdadsf";
console.log(num.prop_1);
Using the Number constructor returns a number object which you can see by typing the following line:
console.log(typeof num); // object
While in the first case:
var num = 1;
console.log(typeof num) // number
EDIT 2: When you invoke a method on a number literal or string literal for instance, then that primitive is wrapped into its object representation automatically by the language for the method call to take place, for example:
var num = 3;
console.log(num.toFixed(3)); // 3.000
Here num is a primitive variable, but when you call the toFixed() metohd on it, it gets wrapped to a Number object so the method call can take place.
EDIT: In the first case, you created a string like this first var str = new String(), but then you changed it to str = "asdf" and then assigned the property str.var_1 = "1234".
Of course, this won't work, because when you assigned str = "asdf", str became a primitive type and the Object instance that was originally created is now gone, and you can't add properties to primitives.
In the second, it didn't output undefined like you said, I tested it in Firebug and everything worked correctly.
EDIT 3:
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.
This is taken from MDN Documentation, when you use string like that var p = String(3) it becomes a conversion function and not a constructor and it returns a primitive string as you can see from the quote above.
Regarding your second comment, I didn't understand how my comment has been defied, because if you try to console.log(p.pr) you'll get undefined which proves p is a primitive type and not an object.
If an array is just an object in the same way a string or a number is an object,
An array is different than strings, numbers, booleans, null and undefined. An array IS an object, while the others in the list are primitive values. You can add properties to the array just like you would with any other object, anything different being just what makes arrays special (the length property you mentioned for example). You cannot add properties or call methods on primitive values.
In this previous answer i talked about the use of Object wrappers over primitive values. Feel free to read it to see more about Object wrappers. The following will be a very short example:
console.log('TEST'.toLowerCase()) // 'test'
While it may seem that the toLowerCase method is called on the string 'TEST', in fact the string is converted automatically to a String object and the toLowerCase method is called on the String object.
Each time a property of the string, number or boolean is called, a new Object wrapper of the apropriate type is created to get or set that value (setting properties might be optimized away entirely by the browser, i am not sure about that).
As per your example:
var num = 1; // primitive value
num.prop_1 = "a string"; // num is converted to a Number, the prop_1 property is set on the Object which is discarded immediately afterwards
console.log(num); //1 // primitive value
console.log(num.prp); // num is converted to a Number, which doesn't have the prp property
My example:
Number.prototype.myProp = "works!";
String.prototype.myFunc = function() { return 'Test ' + this.valueOf() };
Boolean.prototype.myTest = "Done";
console.log(true.myTest); // 'Done'
console.log('really works!'.myFunc()); // 'Test really works!'
var x = 3;
console.log(x.myProp.myFunc()); // 'Test works!'
console.log(3['myProp']); // 'works!'
On the other hand:
console.log(3.myProp); // SyntaxError: Unexpected token ILLEGAL
The number isn't necessarily treated differently, that syntax just confuses the parser. The following example should work:
console.log(3.0.myProp); // 'works!'

Categories

Resources