var hello = 'hello';
Array.prototype.unshift.call(hello, '11') // gives error
Array.prototype.join.call(hello, ', ') // works, why??
can someone explain to me why .join works and why .unshift doesn't
Because strings are immutable, and unshift tries to assign to an index (property) of the string, as in
"hello"[4] = '1'
Reference: http://www.ecma-international.org/ecma-262/6.0/#sec-string-exotic-objects:
A String object is an exotic object that encapsulates a String value and exposes virtual integer indexed data properties corresponding to the individual code unit elements of the String value. Exotic String objects always have a data property named "length" whose value is the number of code unit elements in the encapsulated String value. Both the code unit data properties and the "length" property are non-writable and non-configurable.
join doesn't assign anything and only reads properties, therefore it works with any object that has .length.
Try this:
String.prototype.unshift = function(el) {
let arr = [this];
arr.unshift(el);
return arr.join("");
}
var s = "BCD";
s = s.unshift("A");
console.log(s); // ABCD
Related
I have declared an array a = [1,2,3,4,5]
When I write a[1] it returns 2 which is perfectly fine but when I write a['1'] it also gives me 2 instead of giving an error.
I was expecting an error there. Why does it behave like that??
All property names are strings.
If you pass a number, it gets converted to a string before being used to look up the property value.
console.log(1 == '1');
In JS an Array is basically an Object and thus mostly behaves like one. In this case, these are equivalent as long as you dont access Array's .length or try iterating a:
const a = {"0": foo};
const b = ["foo"];
Also this would work:
const a = ["foo"];
a.bar = "baz";
console.log(a);
So that a[1] and a['1'] are equivalent is exactly what's to be expected.
First of all, array is also object having property names as 0,1,2,....n
Property names must be strings. This means that non-string objects cannot be used as keys in the object. Any non-string object, including a number, is typecasted into a string via the toString method. [Ref]
Unintentionally, In my project I had used the following code and I was surprised to see that is working:
HTML
<span id="output"></span>
Javascript
var myObject = {
'a': '----First---',
'b': '----Second---',
'c': '----Third----'
};
var myArray = ['a'];
// First Case
output.innerHTML = myObject[myArray];
var myArray2 = ['b'];
// Second Case
output.innerHTML += myObject[myArray2];
var myArray3 = ['a', 'b'];
// Third Case
output.innerHTML += myObject[myArray3];
Output
----First-------Second---undefined
Jsbin Link: http://jsbin.com/godilosifu/1/edit?html,js,output
I am directly accessing array reference within Object which should be undefined in all the cases but strangely When array is of Size 1, it always gets the first element and use that as the object key.
I just want to know what is this concept called and why is this happening ?
Because the property name has to be a string, it is type cast into one using the toString() method. The reason that your third example is undefined is that ['a', 'b'].toString() equals 'a,b', which is not a property in your object.
Property names
Property names must be strings. This means that non-string objects
cannot be used as keys in the object. Any non-string object, including
a number, is typecasted into a string via the toString method.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors
Worth noting is that in ECMAScript 6, there is a new collection type called Map, which allows you to use any object as a key without type coercion.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
When you pass the array to the object as a Key, it is calling toString() on it. This is because all Keys in Javascript are Strings.
['a'].toString() is "a"
myObject['a'] is "----First----"
See: Keys in Javascript objects can only be strings?
It's auto-casting. In Javascript, only strings can be indexes into an object's properties. myObject is not an array, it's an object. Even though you're using the brackets to access it's properties, it is not the same meaning as brackets used on an array object.
Due to object properties only being allowed to be named by strings, the compiler auto-casts your array to a string (essentially calling it's native toString() function, which for an array, joins all the elements with a comma).
So when you pass your array to the object's property accessor/index, it does this:
myArray1 ==> "a";
myArray2 ==> "b";
myArray3 ==> "a" + "," + "b" ===> "a,b";
So I've tried to use the map() method as follows:
words = ["One", "Two"];
words = words.map(function(currentValue)
{
alert(currentValue[0]);//Output: O Then: T
currentValue[0] = "A";
alert(currentValue[0]);//Output: O Then: T
return currentValue;
});
Why is it that currentValue[0] is not getting assigned the value "A"?!?
Your attempting to assign to a string at a specific position via its index, this is not possible as Strings are immutable. If you want to change a string you need to create a new one.
As Alex K correctly points out, strings are immutable and you cannot modify them.
Since you are using a .map(), the thing to do here is just construct a new string and return that:
var words = ["One", "Two"];
words = words.map(function (currentValue) {
return "A" + currentValue.substring(1);
});
console.log(words); // outputs ["Ane", "Awo"];
As a rule of thumb, you should not try to use .map() to modify existing values. The purpose of .map() is to produce a new set of values, and leave the original ones untouched.
In JavaScript String is the primitive type, so you cannot mutate it.
String , Number , Boolean, Null, Undefined, Symbol (new in ECMAScript 6) are primitive types.
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!'
What is the JavaScript equivalent function for CreateObject("Scripting.Dictionary")?
I have to convert following two statements from VBScript to JavaScript, anyone can help me to find a solution.
Set oInvoicesToCreate = CreateObject("Scripting.Dictionary")
If Not oInvoicesToCreate.Exists(cInvoiceID) Then
oInvoicesToCreate(CStr(cInvoiceID)) = ""
End If
var oInvoicesToCreate = {};
if(oInvoicesToCreate[cInvoiceID] === undefined){
oInvoicesToCreate[cInvoiceID] = "";
}
You probably don't want to check the hasOwnProperty method because you'll want to check if anything in the prototype chain has that property as well and not overwrite it. checking with the []s will let you know if any property on any prototype items have the property as well.
As bluetoft says in this answer, in Javascript you can use a plain object instead. However, there are a few differences between them that you should be aware of:
First, a Dictionary's keys can be any type:
var dict = new ActiveXObject('Scripting.Dictionary');
dict(5) = 'Athens';
console.log(dict('5')); //prints undefined
whereas any value used for a Javascript object's key will be converted to a string first:
var obj = {};
obj[5] = 'Athens';
console.log(obj['5']); // prints 'Athens'
From MDN:
Please note that all keys in the square bracket notation are converted to String type, since objects in JavaScript can only have String type as key type. For example, in the above code, when the key obj is added to the myObj, JavaScript will call the obj.toString() method, and use this result string as the new key.
Second, it is possible to set a Dictionary to treat differently cased keys as the same key, using the CompareMode property:
var dict = new ActiveXObject('Scripting.Dictionary');
dict.CompareMode = 1;
dict('a') = 'Athens';
console.log(dict('A')); // prints 'Athens'
Javascript key access via [] doesn't support this, and if you want to treat differently-cased keys as the same, you'll have to convert the potential key to lowercase or uppercase before each read or write.
For your specific scenario, neither of these differences matter, because the keys are numeric strings (1) which have no case (2).