Why are objects like this?
mari tang
Posted on September 6, 2018
I went to a workshop was called "JavaScript The Easier Parts: Objects, Functions, Execution Context". I thought that it was going to be a very basic overview of functions and scope, teaching me that a local variable isn't accessible outside of the function where it's defined, or how to declare an object in JS, or store or call its methods. All stuff I'd done before in other tutorials. I got those things, yeah, but I also got a lot of the theory and fundamentals that I was hoping for. The instructor laid out a fairly comprehensive model of the call stack, global memory, global execution context, and locally scoped execution context/memory.
Being taught that functions, objects, variables, and primitives are all stored in memory when initialized, and that using any of them just means calling the version that's currently stored in memory- that explains why reassigning a variable works: you're just rewriting what's stored in the (global or local) memory, and then accessing that stored value. The value that's stored in memory isn't necessarily the same one that you might explicitly see in the code itself.
I also learned about objects and pointers in JS, and that an array is an object in javascript. In order to save space, an object is a collection of pointers that store the location of data saved inside of them. One particularly insidious result of this is that when you assign, say object2 = object1, you're not copying the properties and methods of object1 into object2. You're only copying the pointers (or is it that you're having the pointers of object2 point at the pointers of object1? Either way, it seems to work the same).
This has a couple of interesting side effects. One is that if we're assigning object2 = object1, changing any of the properties in object2 will also change the same property in the same way in object1. This is because both are pointing at the same place in memory.
Here's how it works for objects:
let objA = {property1: 1};
let objB = objA;
(objA.property1 == 1) // returns true
(objB.property1 == 1) // also returns true
// now let's reassign objB:
objB.property1 = 2;
// and we see this behavior:
(objB.property1 == 2) // returns true
(objA.prooperty1 == 2) // ALSO RETURNS TRUE!
Contrast this with how primitives work.
let a = 1;
let b = a;
(a == 1) // returns true
(b == 1) // returns true
//now let's reassign b:
b = 2
// now we see:
a == 1 // still returns true
b == 2 // returns true
What trips me up is that we didn't do anything to objA after its initial assignment, but because objB points at objA, which points at the properties and values stored in memory, changing objB.property1 still changes objA.property.
That's kind of an unintuitive thing for me, but what really tripped me up in finishing my last problemset was that arrays are objects in javascript. That means that, when building a function to deal with an array, I can't just do this:
function arrayFunction(array){
array2 = array;
}
and expect to be able to manipulate array2 without damaging the data in the array that's passed as an argument to arrayFunction. I haven't worked out the most elegant way to get it done, but I do know I can iterate through the values stored in an array and copy them one by one to a new array in order to ensure that they're stored in a separate block of memory, which I can manipulate or destroy without affecting the original array.
Now, if that wasn't enough, we also have certain things to consider when comparing objects.
Remember I mentioned that objects store data by essentially having a pointer directing you to where that data is stored in memory? Well, when we compare objects, we're really checking if they're pointing at the same place in memory. Let me show you an example.
let objA = {property1: 1};
let objB = objA;
objA == objB //returns true, as expected
//but let's make a third object here:
let objC = {property1: 1};
//and let's do some comparisons!
objC == objA // returns false
objC == objB // also returns false!
So, despite having the same number of properties, the same name for the property, and the same value, objC doesn't point at the same memory address where that data is stored, and therefore isn't the same as objA or objB. Instead, we have to individually check whether they have the same number of properties, whether the names of those properties are the same, and whether their values are the same by iterating through the object. If there are objects stored within the object, then we have to do the whole thing recursively until we get to the ultimate properties and values.
Whew.
Now, in Javascript, arrays are objects. That means all of this stuff applies to comparing arrays.
Luckily, it's much simpler to do this, because we can easily iterate through any array with a for loop.
for (let i=0; i<array.length; i++){
console.log(array[i]);
}
for instance, will print all values of an array called array. We just have to nest two loops like this, and we can reliably do a comparison between two arrays.
So yeah, my brain is frying, and you can probably see it oozing out of my ears. I'll be headed back for a second workshop today, and it's gonna be about recursion. I expect I'll be nice and crispy by the end of it.
Posted on September 6, 2018
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.