First… a quick note.
const s = "I'm not really an object";
s.message = "prove it!"
console.log(s.message);
Arrays
are actually just objects (they're not a separate type on their own)They're pretty unremarkable (whew!) →
'
or "
.length
property contains the number of characters in a stringArrays
though… are a little strange. First - 2 ways to create an Array:
[1, 2, 3]
[]
.length
Array
constructor
Array
constructor!!!Number
argument, it creates an Array
of that length
new Array(2) // [ , , ] !?!?!?!
new Array('abc') // ['abc'] oookaaaay
new Array(2, 4, 6) // [2, 4, 6] sure!
Also, Arrays
are actually just objects. This means that their indexes are properties. →
const a = [];
a[0] = 'ok'
a[4] = 'where are the previous elements?'
console.log(a);
console.log(a.length);
Array
holes varies depending on what you're doing!Strings are object like when you want them to be, and Arrays are secretly objects. They both have a bunch of built-in methods. →
Note that these methods don't change the original string that they're called on: →
"racecar".slice(1, 4)
→ 'ace'
"racecar".slice(0, -1)
→ 'raceca'
These methods modify the array that they're called on! →
compareFunction(a, b)
→ return
-1
, 0
, or 1
index
… and removing howMany
elementsindex
- begin that many elements from endThese don't mutate the array that they're called on. →
These methods may not be so intuitive, so let's go over them in depth. →
splice
removes elements (in place) from an Array, and optionally inserts elements.
start
specifies the index (inclusive) to start modifying the Array
deleteCount
specifies the number of elements to be deleted
start
to be removedstart
specifiedsplice
will only remove elementssplice
removes elements from an existing ArrayUsing the following code, a = [2, 4, 6, 8, 10, 12]
, what is the new content of a… and what is returned… after calling splice (assume a is reset each time)? →
a.splice(2);
a.splice(2, 2);
a.splice(-2);
a.splice(2, 2, 1, 1);
returned: [ 6, 8, 10, 12 ], a: [ 2, 4 ]
returned: [ 6, 8 ], a: [ 2, 4, 10, 12 ]
returned: [ 10, 12 ], a: [ 2, 4, 6, 8 ]
returned: [ 6, 8 ], a: [ 2, 4, 1, 1, 10, 12 ]
They sound the same! They do different stuff though! … totally different stuff.
Think of slice
as a way of copying a sub-Array from an existing an Array.
begin
, is the start index (inclusive) of the sub-Array to be copied out
end
, is the end of the sub-Array (exclusive … so goes up to, but does not include)
What is the output of the following code? →
a = [2, 4, 6, 8];
console.log(a.slice());
console.log(a.slice(1));
console.log(a.slice(1, 3));
console.log(a.slice(-1));
console.log(a);
[ 2, 4, 6, 8 ]
[ 4, 6, 8 ]
[ 4, 6 ]
[ 8 ]
[ 2, 4, 6, 8 ]
What's the output of this code? →
a = [1, 2, 3];
b = a;
a.push(4);
console.log(b);
[1, 2, 3, 4]
Remember… Arrays
are just objects anyway (so, yeah, they're mutable).
A common way of duplicating an Array is to use slice. →
const a = [1, 2, 3];
const b = a.slice();
a.push(4);
console.log(b);
const a = [{}, 2, 3];
const b = a.slice();
b[0].tricky = 'yup, same object';
console.log(a);
[ { tricky: 'yup, same object' }, 2, 3 ]
As of ES6, you can also use spread syntax to copy an Array:
const numbers = [1, 2, 3, 4];
const copy = [...numbers]
Array
literal
const words1 = ['foo', 'bar'];
const words2 = ['baz', 'qux'];
const allWords = [...words1, ...words2]
Objects are mutable. (What does that mean?) →
obj.newProp = 5
Numbers, strings and booleans are all immutable!
Because arrays are mutable, we have to be careful when we work with them.
For example, we can create functions that work on arrays:
(Let's see… →)
Create a function called doubleValues. →
arr
What do you think the following code prints out? →
const numbers = [1, 2, 3];
const doubleValues = function(arr) {
const doubled = [];
for(let i = 0; i < arr.length; i++) {
doubled.push(arr[i] * 2);
}
return doubled;
};
result = doubleValues(numbers);
console.log(numbers);
console.log(result);
[1, 2, 3]
[2, 4, 6]
Create a function called doubleValuesInPlace. →
arr
What do you think the following code prints out? →
const numbers = [1, 2, 3];
const doubleValuesInPlace = function(arr) {
for(let i = 0; i < arr.length; i++) {
arr[i] *= 2;
}
};
const result = doubleValuesInPlace(numbers);
console.log(numbers);
console.log(result);
[2, 4, 6]
undefined
It's not quite pass-by-value, and it's not quite pass-by-reference:
Note that semantics of these phrases differ based on language / community! better to just describe the behavior as above.
Lastly, TL;DR - similar behavior in Java and Python
What is the output of the following code? →
const p = {'x':5, 'y':3};
const changePoint = function(point, distance) {
point.x = 0;
console.log('in function:', point);
};
changePoint(p);
console.log('outside', p);
in function: { x: 0, y: 3 }
outside { x: 0, y: 3 }
We can mutate the original object passed in!
What is the output of the following code? →
const p = {'x':5, 'y':3};
const changePoint = function(point, distance) {
point = {};
console.log('in function:', point);
};
changePoint(p);
console.log('outside', p);
in function: {}
outside { x: 5, y: 3 }
The code outside of the function doesn't see the reassignment!
A function… →
Some references:
If you'd like to find something in an Array, you can use the indexOf
method. (see the docs).
console.log([1, 3, 3, 7].indexOf(3));
console.log([1, 3, 3, 7].indexOf(8));
console.log([1, 3, 3, 7].indexOf(3, 2));
Errrr. It looks like there are a lot of ways to do this. What are they (there are three, and one of 'em is the old classic. →
Which one should we use? →
for
loop is actually the fastest (though, for some engines, you'll have to cache the length!?)forEach
and every are a little bit closer to what you're actually doing (more expressive)
forEach
for of
- ES6 syntax that allows looping over every element in an iterable objectLoop over nums = [1, 2, 3, 4];
and print out double the value of every element. Do this three ways →
// with classic for loop and length caching
for(let i = 0, cachedLength = nums.length; i < cachedLength; i++) {
console.log(nums[i] * 2);
}
// with forEach (define callback first)
const doubleIt = function(x) {
console.log(x * 2);
}
nums.forEach(doubleIt);
(Or with an anonymous function)
// with forEach
nums.forEach(function(num, i) {
console.log(num * 2);
});
Use for…of. It's similar in expressiveness to forEach
, but only available in ES6 →
const words = ['foo', 'bar', 'baz']
for (let w of words) {
console.log(words);
}
break
and continue
!Arrays are really just objects. Sooo this example should look familiar. What will this print out? →
a = [1, 2, 3]
b = a;
b.push(4);
console.log(a);
[1, 2, 3, 4]
(We can use the slice method to copy an Array instead of aliasing: a.slice()
)
When a function is called, it gets an arguments in its context, along with its defined parameters (and this, but we'll talk about that later).
const f = function() {
// btw... ok - I get the funny coercion rules now
console.log("number of args " + arguments.length);
for (let i = 0, j = arguments.length; i < j; i++) {
console.log(arguments[i]);
}
};
f(1, 2, 3);
Think of it as multiple assignment:
const coord = [1, 2];
let [x, y] = coord;
console.log(x); // 1
console.log(y); // 2
const {a, b} = {a: 1, b:2}