Related
This function counts number of all characters of a string into a string. I am not fully understanding the if statement here and how it works.
function getFrequency(string) {
var freq = {};
for (var i=0; i<string.length;i++) {
var character = string[i];
if (freq[character]) {
freq[character]++;
} else {
freq[character] = 1;
}
}
return freq;
};
I thought freq[character] is the property of the object such as A B how does it work with if(freq[character]) also how does the increment of freq[character]++ works?
I have made test like this to try and understand it.
var v = {};
v.h = 3;
v["h"]++;
v["h"] = v["h"] + 1;
v.h++;
v.h = v.h + 2;
console.log(v);
console.log(v["h"]);
I think I can guess the if statement works that if the property exists but I thought JS has an object property calls .hasOwnProperty shouldn't this be used instead?
As for the increments, to my test, it works but I just don't get the reason.
Can someone give me a hand to elaborate this?
Thanks in advance
In javascript, objects are associative arrays. And vice versa. There is no difference between the two concepts.
So defining this variable as an empty object:
var freq = {};
... is actually creating an associative array (like a dictionary or map) with no keys added yet.
Moving on, let's take an input string like eek. The code here will look at the first letter and treat freq[character] the same as freq['e'], which is the same as freq.e.
In this code, the initial value of any letter in the freq object is undefined. So that initial if() check for the first "e" in our string actually looks like this:
if(undefined)
Javascript has the concept of "truthy" and "falsy" values; anything in javascript can be evaluated as a boolean, and (in most cases) a sensible result is achieved. Looking at undefined, Javascript will simply treat this a falsy value, fall to the else block, and therefore execute this code:
freq[character] = 1;
As already established, this is the same thing as freq.e = 1;
Now when the loop continues to the next letter (also an "e"), javascript will end up evaluating the expression if (1). Javascript treats this and all other non-zero numbers as "truthy", so this time will execute the following line:
freq[character]++;
Again, that's the same as freq.e++, where freq.e had a value of "1" that can now be incremented to "2".
One more time through the loop for the final letter "k". This time we get freq.k, which is still undefined. Undefined is falsy, so control falls to the else block, and freq.k is set to "1".
Now you can see how we can start to increment letters in the array as you find them in the string, even though it appears that you never defined an array in the first place, never set any values to anything other than "undefined", and never had a real boolean value to check against.
if (freq[character]) checks if the value is "truthy". That is, it's not false, null, undefined or 0. The first time we encounter any character the value will be undefined, since the object literal is created empty, so the "truthy" check will fail and control will fall to the else block.
So when we first see a specific letter set the value to 1 (which is now "truthy").
Any subsequent encounters of that letter just increment the value, which would be equivalent to say freq[character] = freq[character] + 1;. The increment syntax is just a shorthand.
if (freq[character]) checks if the object freq has a property on it with the value of character as the name. The result of this expression evaluates to true or false.
It can be more explicitly stated, as the following non-exhaustively illustrates:
if (freq[character] == null)
or
if (typeof freq[character] === 'undefined')
The danger in not being explicit when evaluating if an object is undefined or null, is if it is actually set to a different type that evaluates to true or false (0, 1, '0', true, false).
Can anyone explain me that what happens when I add a variable of type object with a numeric value?
I did the following in chrome dev console :
> //Denotes input in dev console
< //Denotes output
> var a={};
< undefined
> a
> Object {}
> a=a+1;
< "[object Object]1"
> a
< "[object Object]1"
> b=2
< 2
> a+b
< "[object Object]12"
Also note that within bracket First is lower-case object and 2nd is uppercase Object.
Thanks.
Rules for JavaScript and mixed-type operations are quite convoluted and depend on the operation, for example for + an extremely simplified description is:
If both are number then the arithmetic sum is performed
If any of the two is not a number then both are converted to string and concatenation is performed
The string conversion of an object (unless you defined what to do) is just "[object Object]" and that explains the results you described in the question.
Note that this is not the whole truth... things are much more convoluted and a full description require concepts like .toValue members, special cases for Date objects and so on. Moreover things are getting more and more complex as time passes (ES6 behavior for example requires introduction of concepts like distinction between "exoticToPrim" and "OrdinaryToPrimitive").
Unfortunately I am not kidding.
In case you want to understand better pay attention when writing test programs that you cannot trust the == operator to check what the result is because the rules for that equality operator are even more convoluted (bordering total madness, actually). == in Javascript is just a bug-hiding shelter and should have no place in any code (if strangely enough you really want what it does then implement that behavior explicitly and comment on why it is needed instead of just using ==).
Always use ===.
a = a+1
It first looks if a is a numerical value or not, if it is then the behaviour is normal mathematical operation.
Otherwise it typecast a in a string and proceed with normal string concatenation. The default conversion from an object to string is [object Object], so a+1 will be [object Object]1
Try doing stringify({});, it prints [object Object]
When you use plus operator object a converts to string using toString method. And then strings a and b concatenate
This is called as type coercion. variable a cannot be added with 1 technically. So it coerced to string and then get concatenated with the numeric 1.
var a = {} + 1; //[object object]1
//--> string form of {} will be [object object]
//--> + operator will use its overload concatenation when it is used over a string.
//--> The type of value returned after this operation will be a string.
You will love this one: https://youtu.be/20BySC_6HyY?t=1m26s It's all about JavaScript trying to correct your variable types. It has some crazy edge cases. e.g.
"+" is to "add" 2 strings to form new one or to add 2 numbers to make a "sum". What is in your situation - you are trying to change variable types to strings or numbers and make new string or number. Js decided to make new string:
var a = {}
// Output: Object {}
a.toString();
// Output: "[object Object]"
To learn more i highly recommend this:
http://jibbering.com/faq/notes/type-conversion/
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
At wtfjs, I found that the following is legal javascript.
",,," == Array((null,'cool',false,NaN,4)); // true
The argument (null,'cool',false,NaN,4) looks like a tuple to me, but javascript does not have tuples!
Some quick tests in my javascript console yields the following.
var t = (null,'cool',false,NaN,4); // t = 4
(null,'cool',false,NaN,4) === 4; // true
(alert('hello'), 42); // shows the alert and returns 42
It appears to behave exactly like a semicolon ; separated list of statements, simply returning the value of the last statement.
Is there a reference somewhere that describes this syntax and its semantics? Why does it exist, i.e. when should it be used?
You are seeing the effect of the comma operator.
The comma operator evaluates both of its operands (from left to right) and returns the value of the second operand.
The resultant value when a,b,c,...,n is evaluated will always be the value of the rightmost expression, however all expressions in the chain are still evaluated (from left to right).
As already explained this behaviour is caused by , operator. Due to this the expression (null,'cool',false,NaN,4) will always evaluate to 4. So we have
",,," == Array(4)
Array(4) - creates new array with allocated 4 elements. At the time of comparison with the string this array is converted to string like it would be with Array(4).toString(). For arrays toString acts like join(',') method called on this array. So for the empty array of 4 elements join will produce the string ",,,".
Try this alert((null,'cool',false,NaN,4)) and then you can see.
demo
The reason is because the comma operator evaluates all the statements and return the last one.
Think of this line: a = 1, b = 2, c = 3; it will run each expression so in essence it will set the variables to what you want and return the last value (in this case 3)
I'm writing a Google Chrome extension, in JavaScript, and I want to use an array to store a bunch of objects, but I want the indexes to be specific non-consecutive ID numbers.
(This is because I need to be able to efficiently look up the values later, using an ID number that comes from another source outside my control.)
For example:
var myObjects = [] ;
myObjects[471] = {foo: "bar"} ;
myObjects[3119] = {hello: "goodbye"}
When I do console.log(myObjects), in the console I see the entire array printed out, with all the thousands of 'missing' indexes showing undefined.
My question is: does this matter? Is this wasting any memory?
And even if it's not wasting memory, surely whenever I loop over the array, it wastes CPU if I have to manually skip over every missing value?
I tried using an object instead of an array, but it seems you can't use numbers as object keys. I'm hoping there's a better way to achieve this?
First of all, everyone, please learn that what the for-in statement does is called enumeration (though it's an IterationStatement) in order to differentiate from iteration. This is very important, because it leads to confusion especially among beginners.
To answer the OP's question: It doesn't take up more space (test) (you could say it's implementation dependent, but we're talking about a Google Chrome Extension!), and it isn't slower either (test).
Yet my advice is: Use what's appropriate!
In this situation: use objects!
What you want to do with them is clearly a hashing mechanism, keys are converted to strings anyway so you can safely use object for this task.
I won't show you a lot of code, other answers do it already, I've just wanted to make things clear.
// keys are converted to strings
// (numbers can be used safely)
var obj = {}
obj[1] = "value"
alert(obj[1]) // "value"
alert(obj["1"]) // "value"
Note on sparse arrays
The main reason why a sparse array will NOT waste any space is because the specification doesn't say so. There is no point where it would require property accessors to check if the internal [[Class]] property is an "Array", and then create every element from 0 < i < len to be the value undefined etc. They just happen to be undefined when the toString method is iterating over the array. It basically means they are not there.
11.2.1 Property Accessors
The production MemberExpression : MemberExpression [ Expression ] is evaluated as follows:
Let baseReference be the result of evaluating MemberExpression.
Let baseValue be GetValue(baseReference).
Let propertyNameReference be the result of evaluating Expression.
Let propertyNameValue be GetValue(propertyNameReference).
Call CheckObjectCoercible(baseValue).
Let propertyNameString be ToString(propertyNameValue).
If the syntactic production that is being evaluated is contained in strict mode code, let strict be true, else let strict be false.
Return a value of type Reference whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.
The production CallExpression : CallExpression [ Expression ] is evaluated in exactly the same manner, except that the contained CallExpression is evaluated in step 1.
ECMA-262 5th Edition (http://www.ecma-international.org/publications/standards/Ecma-262.htm)
You can simply use an object instead here, having keys as integers, like this:
var myObjects = {};
myObjects[471] = {foo: "bar"};
myObjects[3119] = {hello: "goodbye"};
This allows you to store anything on the object, functions, etc. To enumerate (since it's an object now) over it you'll want a different syntax though, a for...in loop, like this:
for(var key in myObjects) {
if(myObjects.hasOwnProperty(key)) {
console.log("key: " + key, myObjects[key]);
}
}
For your other specific questions:
My question is: does this matter? Is this wasting any memory?
Yes, it wastes a bit of memory for the allocation (more-so for iterating over it) - not much though, does it matter...that depends on how spaced out the keys are.
And even if it's not wasting memory, surely whenever I loop over the array, it wastes CPU if I have to manually skip over every missing value?
Yup, extra cycles are used here.
I tried using an object instead of an array, but it seems you can't use numbers as object keys. I'm hoping there's a better way to achieve this?
Sure you can!, see above.
I would use an object to store these. You can use numbers for properties using subscript notation but you can't using dot notation; the object passed as the key using subscript notation has toString() called on it.
var obj = {};
obj[471] = {foo: "bar"} ;
As I understand it from my reading of Crockford's "The Good Parts," this does not particularly waste memory, since javascript arrays are more like a special kind of key value collection than an actual array. The array's length is defined not as the number of addresses in the actual array, but as the highest-numbered index in the array.
But you are right that iterating through all possible values until you get to the array's length. Better to do as you mention, and use an object with numeric keys. This is possible by using the syntax myObj['x']=y where x is the symbol for some integer. e.g. myObj['5']=poodles Basically, convert your index to a string and you're fine to use it as an object key.
It would be implementation dependent, but I don't think you need to worry about wasted memory for the "in between" indices. The developer tools don't represent how the data is necessarily stored.
Regarding iterating over them, yes, you would be iterating over everything in between when using a for loop.
If the sequential order isn't important, then definitely use a plain Object instead of an Array. And yes, you can use numeric names for the properties.
var myObjects = {} ;
myObjects["471"] = {foo: "bar"} ;
myObjects["3119"] = {hello: "goodbye"};
Here I used Strings for the names since you said you were having trouble with the numbers. They ultimately end up represented as strings when you loop anyway.
Now you'll use a for-in statement to iterate over the set, and you'll only get the properties you've defined.
EDIT:
With regard to console.log() displaying indices that shouldn't be there, here's an example of how easy it is to trick the developer tools into thinking you have an Array.
var someObj = {};
someObj.length = 11;
someObj.splice = function(){};
someObj[10] = 'val';
console.log(someObj);
Clearly this is an Object, but Firebug and the Chrome dev tools will display it as an Array with 11 members.
[undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, "val"]
So you can see that the console doesn't necessarily reflect how/what data is actually stored.
I would simply use a constant prefix, to avoid such problems.
var myObjects = {};
myObjects['objectId_'+365] = {test: 3};
will default to Js-Objects.
You could attempt to do something like this to make it loud and clear to the JIST compiler that this is a more objecty-ish array like so:
window.SparseArray = function(len){
if (typeof len === 'number')
if (0 <= len && len <= (-1>>>0))
this.length = len;
else
new Array(len); // throws an Invalid array length type error
else
this.push.apply(this, arguments);
}
window.SparseArray.prototype = Array.prototype