I'm currently reading 'Singe Page Web Applications' book. I encountered the following example:
// This is single pass encoder for html entities and handles
// an arbitrary number of characters
encodeHtml = function ( input_arg_str, exclude_amp) {
var input_str = String( input_arg_str), regex, lookup_map;
...
return input_str.replace(regex, function ( match, name ){
return lookup_map[ match ] || '';
});
};
I wonder, what is the purpose of using function String() with argument input_arg_str. I know that by using String() function I can convert different object to string, but I never met with such a feature using String().
I'm curious what you think about this and top thank you for your help.
#Amit Joki's answer is correct, of course, but there are several ways you could convert an object to a string, why use String(...)?
I'd guess the main reason here is that it safely handle's null and undefined whereas .toString would obviously fail.
String(undefined) // "undefined"
String(null) // "null"
In short, it's a more defensive way to convert an object to a string than .toString. Here's a note about it on MDN:
It's possible to use String as a "safer" toString alternative, as
although it still normally calls the underlying toString, it also
works for null and undefined.
I believe you get the same results with string concatenation:
var input_str = '' + input_arg_str; // also handles `null` and `undefined`
Can't say I've ever found a reason to use it, but MDN does suggest there are some subtle differences between string literals and string objects (emphasis mine):
Note that JavaScript distinguishes between String objects and primitive string values. (The same is true of Boolean and Numbers.)
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.
String primitives and String objects also give different results when using eval. Primitives passed to eval are treated as source code; String objects are treated as all other objects are, by returning the object.
For these reasons, code may break when it encounters String objects when it expects a primitive string instead, although generally authors need not worry about the distinction.
source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String
As others have said, in the context of the code you posted, it does ensure that whatever was passed as input_arg_str is converted to an actual string.
Related
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
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.
It seems in Number objects, numeric values can be referenced directly using "this" instead of this.valueOf() or something like "this.value", for example:
Number.prototype.printPlusOne=function(){
var tmp=this+1;
alert(tmp);
}
var n=new Number("5");
n.printPlusOne();
And why is this possible(using "this" directly instead of "this.valueOf()" in the addition above)?
I didn't find this feature in the Number specification, Did I missed something?
And further more, Is this automatic conversion feature used in other classes of objects?
Neither operand of the + operator is a string, so JavaScript calls valueOf to implicitly convert the Object (a Number, in this case) to a primitive value, in order to perform numeric addition. Quoting David Flanagan:
If the object has a valueOf() method that returns a primitive value, JavaScript converts (if necessary) that primitive value to a number and returns the result.
So, this is implicitly converted to its primitive value.
If you did something silly like override Number.valueOf:
Number.prototype.valueOf = function() {
return 10;
}
then your function would alert 11 instead.
Not sure what you're trying to accomplish here, but:
Number.prototype.print=function(){
alert(this.valueOf());
}
var n=new Number("5");
n.print();
In JavaScript a String is a primitive value.
But is also a String object...
A primitive value is a value put directly into a variable.
So my question is:
var d = "foo";
does d contain directly foo or a reference to a string object like other languages?
Thanks.
If I understand it correctly, d will contain the string literal "foo", and not a reference to an object. However, the JavaScript engine will effectively cast the literal to an instance of String when necessary, which is why you can call methods of String.prototype on string literals:
"some string".toUpperCase(); //Method of String.prototype
The following snippet from MDN may help to explain it further (emphasis added):
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.
This is all explained in detail in the specification, but it's not exactly easy reading. I asked a related question recently (about why it is possible to do the above), so it might be worth reading the (very) detailed answer.
if you define
var d = "foo";
than d contains directly foo
but, if you define
var S = new String("foo");
then S is an Object
Example:
var s1 = "1";
var s2 = "1";
s1 == s2 -> true
var S1 = new String("2");
var S2 = new String("2");
S1 == S2 -> false
I think that every variable in Javascript actually represents an Object. Even a function is an Object.
I found two useful articles detailing this, located here and here. Seems like primitive types in JavaScript are passed by VALUE (i.e. when you pass if to a function it gets "sandboxed" within the function and the original variable's value won't change), while reference types are passed, you guessed it, by REFERENCE and passing it through to a function will change the original variable.
Primitive types in JavaScript are text (string), numeric (float / int), boolean and NULL (and the dreaded "undefined" type). Any custom objects, functions or standard arrays are considered reference types. I haven't researched the Date type though, but I'm sure it will fall into the primitive types.
Found this page about javascript variables, seems that:
Primitive type for javascript are booleans, numbers and text.
I believe there are no primitives in Javascript, in the Java sense at least - everything is an object of some kind.
So yes it is a reference to an object - if you extend the String object, d would have that extension.
If you mean primitives as in those types provided by the language, you've got a few, boolean, numbers, strings and dates are all defined by the language.
MDN states:
primitive, primitive value
A data that is not an object and does
not have any methods. JavaScript has 5
primitive datatypes: string, number,
boolean, null, undefined. With the
exception of null and undefined, all
primitives values have object
equivalents which wrap around the
primitive values, e.g. a String object
wraps around a string primitive. All
primitives are immutable.
So when we call a "s".replace or "s".anything is it equivalent to new String("s").replace and new String("s").anything?
No, string primitives do not have methods. As with numeric primitives, the JavaScript runtime will promote them to full-blown "String" objects when called upon to do so by constructs like:
var space = "hello there".indexOf(" ");
In some languages (well, Java in particular, but I think the term is in common use) it's said that the language "boxes" the primitives in their object wrappers when appropriate. With numbers it's a little more complicated due to the vagaries of the token grammar; you can't just say
var foo = 27.toLocaleString();
because the "." won't be interpreted the way you'd need it to be; however:
var foo = (27).toLocaleString();
works fine. With string primitives — and booleans, for that matter — the grammar isn't ambiguous, so for example:
var foo = true.toString();
will work.
The technically correct answer is "no".
The real-world answer is "no, but it will work anyway". That's because when you do something like
"s".replace()
the interpreter knows that you want to actually operate on the string as if you had created it with
var str = new String("s")
and therefore acts as if you had done that.