I have come across an interesting piece of code:
function repeat(str,x) {
return Array(x+1).join(str);
}
repeat("wow", 2);
The outcome of this is a string "wowwow". However, I have no idea what this Array(x+1) is actually doing. And very interesting thing is that if I just use Array(x) it prints the str only once and not twice as expected.
When I console.log Array(x+1) it gives this strange output:
Array(x+1) (3) [empty × 3]
I am aware that there exists a repeat() method on strings which can be used happily to achieve the same result as the presented function. But as I've come across it, I would like to know the mechanism behind Array(x+1). I also know what an array or new Array() is. But this I see for the first time.
Array is specified such that new is optional. From the spec:
When called as a constructor it creates and initializes a new Array exotic object. When Array is called as a function rather than as a constructor, it also creates and initializes a new Array object. Thus the function call Array(…) is equivalent to the object creation expression new Array(…) with the same arguments.
(my emphasis)
To my surprise, the MDN page is not at all clear about this. If I get time, I may have to fix that...
As you can see in console Array(x+1) creates array with 3 empty elements (as far as x = 2). Then you join these elements with string wow so you have:
empty element + "wow" + empty element + "wow" + empty element = "wowwow"
Array(x+1) creates an array of 3 elements all containing empty elements.
Later you are joining these empty elements with the string wow, thus returning:
empty + "wow" + empty + "wow" + empty => wowwow
It is a function that creates an array.
Things like this you should really just try in you console before asking.
These things can be done in Javascript even though they are somewhat contra intuitive:
function A() {
return new Array();
}
let myA1 = A(); // returns an array
let myA2 = new A(); // also returns an array.
EDIT:
The reason is that Javascript is a prototypal language and a "Class" is just a function that we new. If that function is not returning anything we get a new instance of in our case A and if the function returns some other object, that object gets returned.
What is does is to create an array with size x+1(3, in this example). And filling it each cell with the str variable value.
In this code I create an array of size 3 cells and fill them with the string "yolo".
$(document).ready(function(){
var str = "yolo";
console.log(Array(4).join(str));
})
Example fiddle: https://jsfiddle.net/6o90fv9c/
Related
I'm always confused when I hear strings are primitives in JS, because everybody knows that string has different methods like: length, indexOf, search etc.
let string = "Please locate where 'locate' occurs!";
let pos = str.lastIndexOf("locate");
let position = str.search("locate");
It's true that everything in JavaScript is just like object because we can call methods on it. When we use new keyword with string it becomes an object otherwise it's primitive type.
console.log(typeof new String('str')); //object
console.log(typeof 'str'); //string
Now whenever we try to access any property of the string it box the the primitive value with new String()
'str'.indexOf('s')
is equivalent to
(new String(str)).indexOf('s').
The above process is called as "Boxing". "Boxing" is wrapping an object around a primitive value.
Strings are not objects, they are native types, like numbers, but if you want to access the method on it they are boxed with String object. The same happen with numbers you can call (10).toString() but in fact you're calling toString on Number instance that wraps 10, when you call the method.
Not certainly in that way.
If you try to use a class method for a primitive, the primitive will be temporarily wrapped in an object of the corresponding class ("boxing") and the operation will be performed on this object.
For example,
1..a = 2;
It's equal to:
num = new Object(1.);
num.a = 2;
delete num;
So, after executing the operation, the wrapper will be destroyed.
However, the primitive itself will remain unchanged:
console.log( 1..a ) // undefined
Every data type is a object in JavaScript.
String, array, null, undefined . Everything is a object in JavaScript
I'm trying to learn Javascript - here's my issue:
In the w3schools.com javascript array examples, they show the sequent example:
var person = [];
person["firstName"] = "John";
person["lastName"] = "Doe";
person["age"] = 46;
document.getElementById("demo").innerHTML =
person[0] + " " + person.length;
An array "person" has been defined, but then they proceed to add some elements whit a "named" index. Then tries to print the HTML document the 0th element and the number of elements of the array, like you would do with a standard array.
The description says:
If you use a named index when accessing an array, JavaScript will
redefine the array to a standard object, and some array methods and
properties will produce undefined or incorrect results.
In fact, person[0] and person.length return respectively "undefined" and "0". Even is person was initially defined as an array, by inserting new named indexes elements, the array should be redefined as an object. But when i try do use the Array.isArray() method for checking it, it returns true:
var person = [];
person["firstName"] = "John";
person["lastName"] = "Doe";
person["age"] = 46;
document.getElementById("demo").innerHTML =
person[0] + " " + person.length;
document.getElementById('test').innerHTML = Array.isArray(person);// returns true
So, why? if, as specified by the tutorial, this has been effectively redefined as a standard object, and the ECMAScript 5 has added the .isArray() method for checking if something is an array and nothing else, shouldn't this return false insted of true?
I'm sure i missed something. If i define person like this:
person = {};
then it returns false, as expected. What is happening here? I just wanted to understand arrays a little bit more, this confuses me. Is this just a broken array, but still an array?
Here's the example (without the Array.isarray() bit, just the default): https://www.w3schools.com/js/tryit.asp?filename=tryjs_array_associative_2
First of all I want to note that the example you took from the w3schools page on arrays, is from the "Associative Arrays" section, which has this important introduction:
Many programming languages support arrays with named indexes.
Arrays with named indexes are called associative arrays (or hashes).
JavaScript does not support arrays with named indexes.
In JavaScript, arrays always use numbered indexes.
This puts the example into context, because it really makes no sense to define a variable as an array and then use string keys. But this was an example to illustrate the point.
Does an Array become an Object?
That JavaScript still considers the variable to be an array is as expected. It becomes an array at the moment of assignment of [], and that does not change by adding properties to that object. Yes, arrays are objects. They just have additional capabilities.
The array did not lose any of its array-like capabilities, but those features just don't work on those string properties, ... only on numerical ones (more precisely, the non-negative integer ones).
You loosely quoted the following statement from w3schools:
If you use named indexes, JavaScript will redefine the array to a standard object.
That is wrong information and leads to your misunderstanding. There is no redefinition happening. When you add properties to any object, then the object does not change "type". It remains an instance of what it was before... An array remains an array, a date object remains a date, a regex object remains a regex, even if you assign other properties to it. But non-numerical properties do not "count" for an array: the length will remain unchanged when you add such properties. The length only reveals something about the numerical properties of the object.
This quote is yet another illustration of what the JavaScript community thinks about w3schools.com, i.e. that it is not the most reliable reference, even though it has its value for learning the language.
Example of adding useful properties to arrays
Having said the above, there are cases where you may intentionally want to make use of such properties on arrays. Let's for example think of an array of words that is sorted:
const arr = ["apple", "banana", "grapefruit", "orange", "pear"];
Now let's add something to this array that denotes that it is currently sorted:
arr.isSorted = true;
We could imagine a function that would allow one to add a value to this array, but which also verifies if the array is still sorted:
function addFruit(arr, fruit) {
if (arr.length && fruit < arr[arr.length-1]) {
arr.sorted = false;
}
arr.push(fruit);
}
Then after having added several values, it would maybe be interesting to verify whether the array needs sorting:
if (!arr.sorted) arr.sort();
So this extra property helps to avoid executing an unnecessary sort. But for the rest the array has all the functionality as if it did not have that extra property.
An object that is set up as an array and then filled as an object becomes a member of both classes. Methods of the Array class will apply to its 'array-ness':
Array.isArray(person);
returns true. Methods of the Object class will apply to its 'object-ness':
typeof(person);
returns object. When it could be either one, the 'array-ness' will prevail, because the variable was first defined as an array:
console.log(person);
will put Array [ ] on the console, because it runs the Array class's logging method. It is displayed as an empty array, since it has no numbered elements, but you could add some:
person[2]=66;
and then console.log would log Array [ <2 empty slots>, 66 ].
I think the polyfill implementation of isArray() will clear your doubt by some extent.
#Polyfill
I wanted to know how javascript arrays work internally, I mean when for example you create a new array.
array = [1,2,3];
It's internally creating a new array: array = new Array();
and then calling Array.push() or similar?
Thanks.
The best resource to find out how javascript internals work is ECMAScript specification itself.
In order to understand what happens internally when you do array = [1, 2, 3] you would need to read section 7.3.16 CreateArrayFromList (elements). Roughly what happens is that first Array object gets created, then each element gets set to this object with CreateDataProperty (7.3.4 CreateDataProperty section) (DefineOwnProperty) internal method.
Then you want to learn what exactly happens when you push element to array. You check 22.1.3.17 Array.prototype.push ( ...items ) section for this. There you will find out that it uses quite different algorithm, namely it sets specific property of an object (7.3.3 Set (O, P, V, Throw) section).
So the answer is no, creating array like a = [1, 2, 3] does not uses same mechanics to insert items as push does. The first one roughly creates new property on (newly created) array object, the push sets property to existing object.
and then calling Array.push() or similar?
No. As you can see in the below example that when array is initialized push (overridden) method is not invoked.
Array.prototype.push = function(){ console.log("adding") };
var array = [1,2,3];
//console.log(array);
But, it is invoked when console statement is executed (after un-commenting the same).
var array = [1,2,3];
It doesn't call push but it's a simpler way to initialize an array when you know the elements in advance.
If you want to add another element you can do it in multiple ways like:
1) array.push(22); // adds integer 22 to the array
or
2) array[4] = 22; // adds integer 22 to the array at index 4
You can even do this:
array[20] = 22; // this will resize the array and keep all the uninitialized elements returns undefined. So array[10] is undefined, for ex.
If you want to know all the details about arrays explained in a simple way I recommend you the book: Secrets of the JavaScript Ninja. It has an entire chapter about arrays.
https://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/1617292850/ref=sr_1_1?ie=UTF8&qid=1519484868&sr=8-1&keywords=javascript+ninja
I am attempting to test a directive but when I mock out the directive a line in the middle of the directive runs an error. Which prevents my tests from running
$scope.getIterations = function (its) {
return new Array(its);
};
Returns
RangeError: Invalid array length
Which makes sense as the argument its returns NaN.
I figured that I could call
var its = [1,2,3];
$scope.getIterations(its)
Inside of a beforeEach but that did not make any difference as the error code returns the same thing.
Maybe I am misunderstanding this code, but I am not sure how to get around this for the unit tests.
The exception is pretty self explanatory: you're passing an Array when new Array() expects variadic arguments as items to insert or a length to pad:
$scope.getIterations = function(its) {
return new Array(its.length);
};
It's not exactly clear what you're trying to do here... Seems like you'd just want to return the argument as-is:
$scope.getIterations = function(its) {
return its;
};
Array construction takes comma separated values which will become the elements of the array, with an exception that if it has only one numeric id, it will generated array of that much length with undefined as its elements.
new Array("a") // ["a"]
new Array("a","b")//["a","b"]
new Array(3,2) //[3,2]
new Array(3) //[undefined x 3]
in your case if the value of its is an array, you can return the variable itself.
return its;
It seems it has to do with new. If your trying to instantiate a new array then try instantiating your array with Array Literal instead of the constructor:
$scope.getIterations = function (its) {
return [its];
};
but as others have pointed out, it's unclear exactly what you want to return, so if its is an array. You can just return its;.
I have an odd problem. I'm trying to use Javascript to fetch me some values from a multidimensional array, and it's giving me some weird output.
Here is my code:
foo = [['3','4'],['5','6']];
for (bar in foo) {
baz = bar[0];
alert(baz);
qux = bar[1];
alert(qux);
}
Here is the output of the above:
// These are all alerts, by the way
0,undefined,1,undefined,$,f,$,c,e,a,c,l,c,l,i,i,n,a,s,l,i,c,o,a,p,g,e,g,e,i,n,c,o,e,r,e,m,f,l,p,i,h,e,r,g
Can somebody tell me what is happening?
Here is a jsFiddle of the problem: http://jsfiddle.net/Jey6w/
Edit:
Here is another jsFiddle, with another layer of "Inception": http://jsfiddle.net/8vyGq/
The output:
// Again, these are all alerts, and * signifies undefined
0**1**$ff$ceaacllcllinnassliicooappgeegeeinncooerremmfllpiiheergg
The JavaScript for ... in loop gives you the names of the object properties, not the values.
Don't use for ... in for real arrays. Use a numeric index or .forEach().
The reason you're getting your output is complicated and uninteresting, since you just shouldn't do that, but here's a start. The property names will be coerced to strings by the for ... in. Thus, on the first iteration, "bar" is the string "0", so ("0")[0] is just "0", and ("0")[1] is undefined because "bar" is a single-character string.
After that, your for ... in loop staggers into some other properties inherited from somewhere; perhaps you're using Prototype or something. The loop then alerts the first two characters of the names of all those other properties.
I could be wrong, but I think it's due to the fact that bar is returning a reference to a property within an object. Changing your selectors to foo[bar][0] works a treat.
foo = [['3','4'],['5','6']];
for (bar in foo) {
alert(foo[bar][0]);
alert(foo[bar][1]);
}
In cases where your object is simply a multi-dimensional array, I would sway array from using the for in statement, as it can select unwanted properties. I would stick to the good old fashioned for(start, stop, increment)
foo = [['3','4'],['5','6']];
for (i = 0; i < foo.length; i++) {
alert(foo[i][0]);
alert(foo[i][1]);
}
Update - jQuery
As there has been mention of jQuery's .each method I thought I'd also post an example of how it could be utilised. The jQuery's each method passes 2 optional parameters, indexInArray, and valueOfElement. Additionally, the jQuery documentation also states that
The value can also be accessed through the this keyword, but
Javascript will always wrap the this value as an Object even if it is
a simple string or number value
With this in mind, we could achieve the same results as previous example, using the following jQuery (jsFiddle):
var foo = [['3','4'],['5','6']];
$.each(foo, function() {
// 'this' is the context of the current item within the array
alert(this[0]);
alert(this[1]);
})