How are symbols displayed in Javascript? - javascript

If I say sym1 = Symbol();, is Symbol function working like below function g,
> g = function(){
| return 2; //return some random unique value based on some internal algo
| }
g()
> var sym1 = g();
> sym1
2
Now when I do var sym1 = Symbol();, and log sym1, the console displays Symbol() instead of displaying the value returned by the Symbol function.
So here's my question: How does the Symbol function work? How is the console able to display Symbol() instead of some value when you type sym1? Can we write such function?

Yes, Symbol is just a function, similar1 to an arbitrary function g() { return something }.
However, unlike the example g in your question, it does not return numbers, but symbols, which are a new primitive value type in ES6.
When I say sym1, console displays Symbol() instead of displaying the value returned by function Symbol.
What do you think is the value returned, and what do you think how it should be displayed?
The number your g function returned is just some collection of 64 bits2. Somehow3, the console derives a base 10 string from that to display the number with the digits you expect.
Now, what is a symbol? It's just a value with an identity, and we don't even know how it is implemented. It's not immediately clear how that could be displayed, or if at all. It's not a number, it's not a string. Maybe some kind of id4?
ES6 however has taken a precaution against this, and every symbol is given a description string5 that can be passed as an optional argument to the Symbol function. Also, ES6 does specify how symbols should be displayed as string in §19.4.3.2. And that's typically what the console uses.
Pretty much this "descriptive string" resembles the way the call to Symbol looked, e.g.
var sym1 = Symbol("my description");
console.log(sym1.toString()); // "Symbol(my description)"
console.log(sym1); // Symbol(my description)6
var sym2 = Symbol();
console.log(sym2.toString()); // "Symbol()"
console.log(sym2); // Symbol()6
1: However, it's a plain function, not a constructor, and cannot be called with new.
2: plus some kind of type information that it's a number, to give the 64 bits a meaning
3: to be explicit, the console probably uses .toString for numbers when it encounters a number
4: Chrome displays such for every object when you take a heap snapshot with the dev tools, for example
5: So yeah, it's a bit more than the unique identity
6: implementation-dependent, depends on your console

Is window['Symbol'] function working like below function g,
Not certain about actual Question ? Though, appear "no"
Here is the confusion, when I say, > sym1 console displays Symbol()
instead of displaying the value returned by function Symbol
Symbol() does not return a function , but a "unique and immutable data type and may be used as an identifier"
See Symbol
A symbol is a unique and immutable data type and may be used as an
identifier for object properties. The symbol object is an implicit
object wrapper for the symbol primitive data type.
var sym = Symbol("foo");
var obj = {};
obj[sym] = 1;
console.log(obj.sym); // `undefined`
console.log(Object.keys(obj)) // `[]`
console.log(obj[sym]); // `1`
See also ES6 In Depth: Symbols

Related

What does the sentence "The element expressions in an array initializer are evaluated each time the array initializer is evaluated" mean?

I was reading David Flanagan's JavaScript: The Definitive Guide, probably the fattest book for JavaScript in the world. When briefly describing array initializers, Flanagan said "The element expressions in an array initializer are evaluated each time the array initializer
is evaluated". What does this means. My practice results made me more confused:
var a = 50;
var b = 70;
var array = [a+b, 50];
console.log (array [0]); //120
a = 60;
console.log (array [0]); //120
var other = array;
console.log (other [0]); //120
I thought the result would be 130 after I change a's value to 60, because the expression is going to be re-evaluated. But it's not that. I know I am completely getting it wrong. Can someone explain what Flanagan is trying to explain in that sentence?
He means that when the array literal expression is ("re"-)evaluated, so will be its contents.
function makeArray() {
return [a];
}
var a = 0;
console.log(makeArray()); // [0]
a = 1;
console.log(makeArray()); // [1]
So, nothing special actually, just default expression behaviour.
You've misquoted the author; what he actually said is
The element expressions in an array initializer are evaluated each time the array initializer is evaluated.
Rather than the term "array initializer", it would be clearer, and more in line with common usage, if he said "array literal". If we adopt the common-sense interpretation of "array initializers" as meaning "initializers for an array-valued variable", then such initializers could be array literals, but could also be any array expression. (Having said that, it does appear that the spec uses the term "array initializer" for "array literal" in Section 12.2.5, so the author's usage is not wrong in that technical sense.) Array literals (basically, anything of the form [...]) can, on the other hand, be used as initializers, but can also be used elsewhere.
What he appears to be trying to say is that an array literal such as
[a]
re-evaluates a each time it itself is re-evaluated, such as when a function is re-executed. If you think about it, that's pretty obvious. It's hard to see how it could work any other way. So the function
function foo(x) { return [x]; }
will return the array [1] when called as foo(1), and the array [2] when called as foo(2), because the array literal [x] is re-evaluated each time the function is called.
This is an entirely different issue from the one that is tripping you up, which is that
var a = 22;
var b = [a];
a = 42;
console.log(b);
does not change b to have the value [42]. This behavior has nothing to do with how array initializers are (re-)evaluated or their component elements are (re-)evaluated. Is has to do with how JavaScript variables and references work. The above would change the value of b if b were storing a dynamic reference to a as its element, but JavaScript has no such notion of dynamically-updatable references. To put it a different way, the console.log(b) line is indeed evaluating b, but that just returns whatever b already is. It does not (re-)evaluate the expression [a] originally used to set b. The fact that b happens to have taken on he value resulting from evaluating [a] is lost immediately after the statement setting the value of b, at which point b now has the value [22].
Consider also the following example, which is completely analogous:
var a = 1, b = 2, c = a + b;
a = 42;
console.log(c);
Here, no-one would expect the expression given as the initial value for c to change when the value of a changes later. c is 3, and it will always be until explicitly re-assigned. In the console(c) line, yes, we are "evaluating" c, but that is merely a matter of retrieving the value of c, not of re-evaluating some expression which happens to have used to assign a value to c in the past. There are some other declarative-style language paradigms where things might behave in that way, but not JavaScript.
Here you assigning the array to array variable and it will store that value until that variable(unless you modify that variable) goes out of scope. In the second statement you're reusing the the same array pointed to by "array" variable. Third statement is just assigning the reference to "array" variable to another variable and access the same element.
Only the first time a+b statement is evaluated and that resulting array is saved as value reference. Last statement is an example of pass by value(Javascript is always pass by value) where copy of "array" variable is created as "other", and "other" also points to same memory reference pointed by "array" variable.

JavaScript - Why does the increment operator modify immutable strings?

In JavaScript, strings are immutable. That means any operation on them returns a new object. Methods like trim, replace and slice don't modify the existing string.
However, I was playing around in jsconsole and found an exception
string = "string";
string + 37;
=> "string37"
string;
=> "string"
The original string hadn't changed here. Here's what happens when I apply the increment operator on the string. Here I am expecting to see string returned.
string++;
=> NaN
string
=> NaN
I was trying to see whether this would return strinh, like it would in some other languages.
Regardless of whether string++ would work, it shouldn't modify existing string objects. Yet it did just that. Does anyone know why?
That ++ operator works similarly to:
string = string + 1;
So, you are re-assigning to that variable. (while the original string remains immutable)
If you run string = string + 1 yourself, you'll notice it results in string1. This is because the 1 is being converted into a string and then treated as an "append". (again, never modifying the original string value)
However, the ++ does not attempt to coerce anything, it simply attempts to add a non-number (ie: string) to a number (1) and the result is NaN.
Here is a simple example:
var baz = "string";
baz = 5;
Certainly we have not modified the value of the string "string" by assigning baz to 5. Instead, we have simply done away with the string altogether and put the value 5 in its place. Similarly, your example does not alter any strings by assigning your variable to NaN.
You expect the variable string to be a constant, but it's not. Furthermore, constant variables and immutable values are different things. You haven't changed the immutable string "string" into NaN; you have substituted the immutable value "string" for a completely different value, NaN.
Your operations create new values by using the immutable string as an operand.
Consider a real constant variable in an environment that supports the const keyword:
> const foo = 5;
> foo++
5
Now consider a constant variable that is an object:
> const bar = {};
> bar.baz = 5
> bar
{ baz: 5 }
> bar = 10;
> bar
{ baz: 5 }
In this case, we mutated the value (because the value is not immutable) but could not alter which value the variable contains. Your example does not use constant variables, so the variable string can freely change its value.

What is the difference between String and new String? [duplicate]

Taken from MDN
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, I thought (logically) operations (method calls) on string primitives should be slower than operations on string Objects because any string primitive is converted to string Object (extra work) before the method being applied on the string.
But in this test case, the result is opposite. The code block-1 runs faster than the code block-2, both code blocks are given below:
code block-1 :
var s = '0123456789';
for (var i = 0; i < s.length; i++) {
s.charAt(i);
}
code block-2 :
var s = new String('0123456789');
for (var i = 0; i < s.length; i++) {
s.charAt(i);
}
The results varies in browsers but the code block-1 is always faster. Can anyone please explain this, why the code block-1 is faster than code block-2.
JavaScript has two main type categories, primitives and objects.
var s = 'test';
var ss = new String('test');
The single quote/double quote patterns are identical in terms of functionality. That aside, the behaviour you are trying to name is called auto-boxing. So what actually happens is that a primitive is converted to its wrapper type when a method of the wrapper type is invoked. Put simple:
var s = 'test';
Is a primitive data type. It has no methods, it is nothing more than a pointer to a raw data memory reference, which explains the much faster random access speed.
So what happens when you do s.charAt(i) for instance?
Since s is not an instance of String, JavaScript will auto-box s, which has typeof string to its wrapper type, String, with typeof object or more precisely s.valueOf(s).prototype.toString.call = [object String].
The auto-boxing behaviour casts s back and forth to its wrapper type as needed, but the standard operations are incredibly fast since you are dealing with a simpler data type. However auto-boxing and Object.prototype.valueOf have different effects.
If you want to force the auto-boxing or to cast a primitive to its wrapper type, you can use Object.prototype.valueOf, but the behaviour is different. Based on a wide variety of test scenarios auto-boxing only applies the 'required' methods, without altering the primitive nature of the variable. Which is why you get better speed.
This is rather implementation-dependent, but I'll take a shot. I'll exemplify with V8 but I assume other engines use similar approaches.
A string primitive is parsed to a v8::String object. Hence, methods can be invoked directly on it as mentioned by jfriend00.
A String object, in the other hand, is parsed to a v8::StringObject which extends Object and, apart from being a full fledged object, serves as a wrapper for v8::String.
Now it is only logical, a call to new String('').method() has to unbox this v8::StringObject's v8::String before executing the method, hence it is slower.
In many other languages, primitive values do not have methods.
The way MDN puts it seems to be the simplest way to explain how primitives' auto-boxing works (as also mentioned in flav's answer), that is, how JavaScript's primitive-y values can invoke methods.
However, a smart engine will not convert a string primitive-y to String object every time you need to call a method. This is also informatively mentioned in the Annotated ES5 spec. with regard to resolving properties (and "methods"¹) of primitive values:
NOTE The object that may be created in step 1 is not accessible outside of the above method. An implementation might choose to avoid the actual creation of the object. [...]
At very low level, Strings are most often implemented as immutable scalar values. Example wrapper structure:
StringObject > String (> ...) > char[]
The more far you're from the primitive, the longer it will take to get to it. In practice, String primitives are much more frequent than StringObjects, hence it is not a surprise for engines to add methods to the String primitives' corresponding (interpreted) objects' Class instead of converting back and forth between String and StringObject as MDN's explanation suggests.
¹ In JavaScript, "method" is just a naming convention for a property which resolves to a value of type function.
In case of string literal we cannot assign properties
var x = "hello" ;
x.y = "world";
console.log(x.y); // this will print undefined
Whereas in case of String Object we can assign properties
var x = new String("hello");
x.y = "world";
console.log(x.y); // this will print world
String Literal:
String literals are immutable, which means, once they are created, their state can't be changed, which also makes them thread safe.
var a = 's';
var b = 's';
a==b result will be 'true' both string refer's same object.
String Object:
Here, two different objects are created, and they have different references:
var a = new String("s");
var b = new String("s");
a==b result will be false, because they have different references.
If you use new, you're explicitly stating that you want to create an instance of an Object. Therefore, new String is producing an Object wrapping the String primitive, which means any action on it involves an extra layer of work.
typeof new String(); // "object"
typeof ''; // "string"
As they are of different types, your JavaScript interpreter may also optimise them differently, as mentioned in comments.
When you declare:
var s = '0123456789';
you create a string primitive. That string primitive has methods that let you call methods on it without converting the primitive to a first class object. So your supposition that this would be slower because the string has to be converted to an object is not correct. It does not have to be converted to an object. The primitive itself can invoke the methods.
Converting it to an full-blown object (which allows you to add new properties to it) is an extra step and does not make the string oeprations faster (in fact your test shows that it makes them slower).
I can see that this question has been resolved long ago, there is another subtle distinction between string literals and string objects, as nobody seems to have touched on it, I thought I'd just write it for completeness.
Basically another distinction between the two is when using eval. eval('1 + 1') gives 2, whereas eval(new String('1 + 1')) gives '1 + 1', so if certain block of code can be executed both 'normally' or with eval, it could lead to weird results
The existence of an object has little to do with the actual behaviour of a String in ECMAScript/JavaScript engines as the root scope will simply contain function objects for this. So the charAt(int) function in case of a string literal will be searched and executed.
With a real object you add one more layer where the charAt(int) method also are searched on the object itself before the standard behaviour kicks in (same as above). Apparently there is a surprisingly large amount of work done in this case.
BTW I don't think that primitives are actually converted into Objects but the script engine will simply mark this variable as string type and therefore it can find all provided functions for it so it looks like you invoke an object. Don't forget this is a script runtime which works on different principles than an OO runtime.
The biggest difference between a string primitive and a string object is that objects must follow this rule for the == operator:
An expression comparing Objects is only true if the operands reference
the same Object.
So, whereas string primitives have a convenient == that compares the value, you're out of luck when it comes to making any other immutable object type (including a string object) behave like a value type.
"hello" == "hello"
-> true
new String("hello") == new String("hello") // beware!
-> false
(Others have noted that a string object is technically mutable because you can add properties to it. But it's not clear what that's useful for; the string value itself is not mutable.)
The code is optimized before running by the javascript engine.
In general, micro benchmarks can be misleading because compilers and interpreters rearrange, modify, remove and perform other tricks on parts of your code to make it run faster.
In other words, the written code tells what is the goal but the compiler and/or runtime will decide how to achieve that goal.
Block 1 is faster mainly because of:
var s = '0123456789'; is always faster than
var s = new String('0123456789');
because of the overhead of object creation.
The loop portion is not the one causing the slowdown because the chartAt() can be inlined by the interpreter.
Try removing the loop and rerun the test, you will see the speed ratio will be the same as if the loop were not removed. In other words, for these tests, the loop blocks at execution time have exactly the same bytecode/machine code.
For these types of micro benchmarks, looking at the bytecode or machine code wil provide a clearer picture.
we can define String in 3-ways
var a = "first way";
var b = String("second way");
var c = new String("third way");
// also we can create using
4. var d = a + '';
Check the type of the strings created using typeof operator
typeof a // "string"
typeof b // "string"
typeof c // "object"
when you compare a and b var
a==b ( // yes)
when you compare String object
var StringObj = new String("third way")
var StringObj2 = new String("third way")
StringObj == StringObj2 // no result will be false, because they have different references
In Javascript, primitive data types such is string is a non-composite building block. This means that they are just values, nothing more:
let a = "string value";
By default there is no built-in methods like toUpperCase, toLowerCase etc...
But, if you try to write:
console.log( a.toUpperCase() ); or console.log( a.toLowerCase() );
This will not throw any error, instead they will work as they should.
What happened ?
Well, when you try to access a property of a string a Javascript coerces string to an object by new String(a); known as wrapper object.
This process is linked to concept called function constructors in Javascript, where functions are used to create new objects.
When you type new String('String value'); here String is function constructor, which takes an argument and creates an empty object inside the function scope, this empty object is assigned to this and in this case, String supplies all those known built in functions we mentioned before. and as soon as operation is completed, for example do uppercase operation, wrapper object is discarded.
To prove that, let's do this:
let justString = 'Hello From String Value';
justString.addNewProperty = 'Added New Property';
console.log( justString );
Here output will be undefined. Why ?
In this case Javascript creates wrapper String object, sets new property addNewProperty and discards the wrapper object immediately. this is why you get undefined. Pseudo code would be look like this:
let justString = 'Hello From String Value';
let wrapperObject = new String( justString );
wrapperObject.addNewProperty = 'Added New Property'; //Do operation and discard

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!'

Primitives and Objects

Definitive JavaScript by David Flanagan makes a distinction between Objects and Primitives.
He defines the primitives as Number, String, Boolean, Null, and Undefined, as does the standard.
However, would it be more accurate to define a primitive, as subset of object, i.e. to call them Primitive Objects.
Because they have their own methods and are complex entities.
Actual Question
Would Primitive Object be more accurate than Object when defining String, Boolean, and Number?
Objects and primitives are distinct:
typeof 42 === "number"
typeof new Number(42) === "object"
new Number(42) !== 42
However, when necessary, primitives are automatically wrapped by temporary objects, which can be automatically converted back into primitives:
(42).toString() === "42"
new Number(42) == 42
new Number(42) + 1 === 43
Especially in the context of the Java and C# programming languages, this sort of behavior is called autoboxing. As wrapper objects have some confusing characteristics, for example:
Boolean(new Boolean(false)) === true
it is good practice to avoid intentionally storing them in variables and instead use primitives whenever possible.
It's not about semantics, look:
var threePrimitive = 3;
var threeObject = new Number(3);
threePrimitive.toFixed(2); // 3.00
threeObject.toFixed(2); // 3.00
threePrimitive.foo = true
threeObject.foo = true;
threePrimitive.foo; // undefined
threeObject.foo; // true
Primitives are wrapped in objects when you try to call a method on them, but after initial use the object is thrown away.
As for how this is stated in the specification, I'm not 100% sure, but here is what I think (based on the tips left by Bergi in one of his answers. Section 11.2.1 states that the accessor properties should be evaluated as follows:
Let baseReference be the result of evaluating MemberExpression.
Let baseValue be GetValue(baseReference).
(...)
Then in 8.7.1 we see the following:
The following [[Get]] internal method is used by GetValue when V is a
property reference with a primitive base value. It is called using
base as its this value and with property P as its argument. The
following steps are taken:
Let O be ToObject(base).
Let desc be the result of calling the
[[GetProperty]] internal method of O with property name P.
If desc is
undefined, return undefined.
If IsDataDescriptor(desc) is true, return
desc.[[Value]].
Otherwise, IsAccessorDescriptor(desc) must be true so,
let getter be desc.[[Get]]. If getter is undefined, return undefined.
Return the result calling the [[Call]] internal method of getter
providing base as the this value and providing no arguments.
NOTE The
object that may be created in step 1 is not accessible outside of the
above method. An implementation might choose to avoid the actual
creation of the object. The only situation where such an actual
property access that uses this internal method can have visible effect
is when it invokes an accessor function.
Would Primitive Object be more accurate then Object when defining
String, Boolean, and Number?
Please note that I'm not saying that numbers are not objects here, I'm pointing out that it appears ambiguous. This is the kind of thing that confuses JavaScript newcomers.
The distinction is mostly academic, but there is one case where it seems ambiguous: literals represent primitive objects except when the literal appears to represent a number. You can't apply a method directly to a literal integer* symbol:
1.toString();
SyntaxError: identifier starts immediately after numeric literal
…but you can apply methods of Numbers:
Number(1).toString();
'1'
…and a name that contains a number is a Number:
x = 4;
x.toString();
'4'
I think this is actually a parsing problem, but I don't really know why the parser can't tell that 1 is a Number as easily as it can tell that "abc" is a String. I suppose it has to do with the semantic ambiguity of the . symbol. (Is it a decimal point or a method operator?)
*JavaScript doesn't actually have integers. I just mean a symbol that consists entirely of [0-9]+.

Categories

Resources