I was just wondering, in most of my projects I have been able to use:
the String() function,
the toString() method and
the JSON.stringify() method (I don't really use this),
to convert data in JavaScript to string without much difference and I was wondering what exactly the difference was between using each of them.
Thanks for reading through, I'll really appreciate your answer.
the String() function
This is the explicit use of the native constructor function that creates and returns a string object when used with the new operator or the string value only when used without new.
the toString() method
This invokes the object's toString() method which returns the string representation of the object, which, if not overridden, usually is something like [object Object], which indicates the instance and the type. Custom objects often will override this inherited method to be able to display the best string representation of that particular object.
JSON.stringify()
This takes an object and converts it into the JSON data format. Without using an optional "replacer" function, all properties that store functions will be stripped out of the string. This is generally used when an object is packaged to hold data and then that data is to be sent over HTTP to another location.
String() is a global string constructor, that accepts anything htat should be converted to string ad returns primitive string. Under the hood this calls Object.prototype.toString()(https://www.ecma-international.org/ecma-262/5.1/#sec-15.5.1.1)
Object.prototype.toString() is a method that return string representation of an object: the value of type String that is the result of concatenating the three Strings "[object ", class, and "]", where class is internal property of object. This function can be overriden
JSON.stringify() method converts a JavaScript value to a JSON string; Boolean, Number, and String objects are converted to the primitive values during the process
Related
From what I have understood, primitive data types such as a string can also have properties ie string can have .includes . Does that mean all primitive data types are converted to objects before being executed. If yes, what is the point of having distinct difference between primitive data types and objects.
Whenever you try to refer to a property of a string s, JavaScript converts the string value to an object as if by calling new String(s). This object inherits string methods and is used to resolve the property reference. Once the property has been resolved, the newly created object is discarded.
Numbers and booleans have methods for the same reason that strings do: a temporary object is created using the Number() or Boolean() constructor, and the method is resolved using that temporary object.
source Javascript: The Definitive Guide. David Flanagan
When you call a property on a string (lower case) primitive, the JS runtime creates a new instance of a String (upper case) object and copies the string primitive value into the new "wrapper" object, then the property or method that you originally called gets called on the wrapper object and then that wrapper object is garbage collected when the statement is completed. This makes it only seem like some primitives have properties when they actually don't.
If yes, what is the point of having distinct difference between
primitive data types and objects.
The point is that primitives are lightweight entities that have a low memory footprint, whereas Objects can do more and therefore require a larger memory footprint. Also, you can't inherit from a primitive, whereas you can from an Object.
If you'll only be doing limited Object operations, using a primitive is the best approach, but if you know that you'll be using many properties of an Object, it's more efficient to create the Object using a constructor from the start to avoid the constant creation and destruction of wrapper objects.
As per this documentation,
The string representations of each of these objects are appended
together in the order listed and output.
Also as per answer
The + x coerces the object x into a string, which is just [object
Object]:
So, my question is
If I do
str = new String("hello")
console.log(str) //prints the string object but not 'hello'
console.log(""+str) //prints "hello"
So, in first case, it simply prints the object (doesn't invoke the toString() method).
But in second case, it doesn't coerce but simply print the primitive value. Why is that so?
Which method does console.log invokes to print the object?
Please note that - this is not a duplicate of this question.
Console API is not a standard API that is defined in any specification but is something that is implemented across all browsers, so vendors are usually at their liberty to implement in their own fashion as there's no standard spec to define the output of any methods in API.
Unless you check the actual implementation of the Console API for a particular browser, you can never be sure. There's a tracker on GitHub listing the differences between implementation from major browsers.
If you look at the implementation in FF (available here - search for log), it has a comment below
A multi line stringification of an object, designed for use by humans
The actual implementation checks for the type of argument that is passed to log() and based on it's type, it generates a different representation.
Coming to your case, log() prints two different values for strings created using literal notation and strings created using String constructor because they are two different types. As explained here, Strings created using literal notation are called String Primitives and strings created using String constructor are called String Objects.
var str1 = 'test';
var str2 = new String('hello');
typeof str1 // prints "string"
typeof str2 // prints "object"
As the types differ, their string representation differs in the Console API. If you go through the code for FF's Console implementation, the last statement is
return " " + aThing.toString() + "\n";
So to answer your question, Console API in FF calls toString() on the argument only if the argument type is not one of {undefined,null,object,set,map} types. It doesn't always call toString() or valueOf() methods. I didn't check the implementation of Chrome, so I won't comment on that.
It does not utilize toString, you can do something like this
clog = function(msg){console.log(msg.toString());}
clog(myObj);
This is more typing but will invoke obj.toString() as well:
console.log(`${obj}`);
console.log(str) calls str.valueOf() I guess.
From JavaScript- The Definitive Guide
Its job is to convert an object to a primitive value. The valueOf() method is invoked automatically when an object is used in a numeric context, with arithmetic operators (other than +) and with the relational operators, for example. Most objects do not have a reasonable primitive representation and do not define this method.
---edit----Sorry,copy the wrong line, I mean the ""+str,since there's a type converting
The documentation on mozilla.org states: "Every object has a toString() method that is automatically called when the object is to be represented as a text value or when an object is referred to in a manner in which a string is expected. By default, the toString() method is inherited by every object descended from Object. If this method is not overridden in a custom object, toString() returns "[object type]", ..."
Sounds logical: A toString() method will be called. So I defined an own "class" and defined a toString() method:
function DataField(name, dataType) {
// ....
}
DataField.prototype.toString = function() {
return this.type.name + " " + this.name;
}
I instantiate an object like this:
var dataField = new DataField("myint", DataType.INTEGER);
I try to output the object respectively the string representation of the object in NodeJS:
console.log(dataField);
console.log("" + dataField);
console.log(dataField.toString());
The first output differs from the other ones. The first one will give some kind of JSON.stringify() representation of the object. toString() is not called automatically as I'd expect it to be. The second and third output will result in exactly what I'd expect:
INTEGER myint
So I'm a bit confused. That means that toString() will not automatically be called though the explanation of mozilla.org suggests. Is this a regular behaviour in NodeJS or did I missinterpret the explanation on mozilla.org or am I missing something else here?
You might think: Well, then let's just call toString() explicitely if necessary and everything is fine. But there is some inconvenience with that. If I create an array of objects and use console.log() to ouput that array, no toString() will be called. Which means: The output generated is useless. This would mean that if I store objects with explicite implementations of toString() within an array in a container object I will have to implement toString() of the container object in a very specific and incovenient way: I must write code to explicitely create a string representations of any array of objects contained in the container object myself. Of course I could do that, but I would intuitively assume a toString() method to be called automatically therefor eliminating such need for explicite implementations.
Regarding NodeJS it seems that finding information is not that easy on this specific problem. So if you know about this topic any help is appreciated. The question is: What is the most elegant way to create a (human readable) string representation of a data model (= a data container object containing lists of other data objects)?
In Node.js, console.log calls util.format, which does not call toString().
I've played with jsperf.com and found that prototyped function is 40x slower than "default" declared function.
String.prototype.contains = function(s){ return !!~this.indexOf(s) } = 220K ops/s
vs.
function isContains(str, s) { return !!~str.indexOf(s) } = 8.5KK ops/s
Here's a jsperf test case
P.S. I know that prototype modification isn't the best case and can be named 'monkey patching' :)
I think it is slow because the string primitive is automatically wrapped with a temporary object each time a method is called.
This also explains the performance boost of new Object("hi").foo() over "hi".foo().
From the MDN docs:
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 and 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.
Nearby:
Why can't I add properties to a string object in javascript?
String object versus literal - modifying the prototype?
Odds are very good that you're replacing a primitive function implemented in C/machine code with a JavaScript body in the monkey-patched version.
I want to know how is the string length of a string calculated in js.
Is is a function call or a class data member.
I want to know what happens when we execute the following code :
a = 'this is a string';
console.log(a.length); // what actually happens at this point?
Also if a do this :
a += ' added something';
console.log(a.length); // at what point is the new length calculated
//and/or updated for the object 'a';
And at last, do I need to store the string length in a temp variable while using a loop over the string or can I directly use the following (which one is faster/processor efficient) :
for(var i=0;i<a.length;i++){
// doing anything here
}
Summing up my question, I want to know the processing behind String.length and which practice is better while looping over strings?
A string is immutable in JavaScript.
a += "somestring" doesn't change the length of a string but makes a new string.
This means there is no "new length", but the length is just part of the definition of the string (more precisely it is stored in the same structure in implementations).
Regarding
for(i=0;i<a.length;i++){ // did you forget the 'var' keyword ?
a not so uncommon practice (if you don't change a) was to optimize it as
for (var i=0, l=a.length; i<l; i++)
in order to avoid the reading of the length but if you compare the performances with modern engines, you'll see this doesn't make the code any faster now.
What you must remember : querying the length of a string is fast because there is no computation. What's a little less fast is building strings (for example with concatenation).
Strings are a primitive type. At least that's what the documentation says. But we can access the length of the string as if we are accessing the property of an object(with the dot notation). Which indicates it's an object, Right?
Turns out, whenever we make a call from the string primitive to some property using the dot notation (for example, say length), the Js engine will take this primitive string and wrap it into an equivalent wrapper object, which is a String object. And then, the .length on that String object returns the length.
Interesting thing to note here is, that when we do something like this, our string still stays the same primitive string during all of this. And a temporary object is created to make our string operation work. Once the required property is fetched, this temporary object is deleted from the memory.
Hope this gives some high level understanding.
I'm answering your first question.
I'm also curious about this puzzle so I did some search myself, ended up finding -
Based on String documentation from Mozilla:
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.
So as I understand, when you use somestring.length, the primitive string will first be wrapped as a String object, and then since the object has its property length, so it's just a internal method call to access and return.