Got through a few pieces of example code in C
. Honestly the book is helping me build a better level of comfort with what is going on. I really appreciate how close the language is to being bare. It helps me operate outside of all these black boxes. For example, I am still reading up on JavaScript at the same time and the amount of operations that are assumed for me as a programmer really pulls me away from what’s going on under the hood. I guess if I would have to compare, maybe it’s like driving a manual vs automatic transmission car. I could be wrong but for a learner like myself, I appreciate how much I need to understand to get what I want out of C
. JavaScript makes it quicker at first but then you get complacent and then you get bugs or performance issues as you try to do more complicated stuff. But I’m going to address all of this for both languages. Step by step!
TLDR;
Okay, so here are the highlights of what I did:
- Continued to work on the “Technical Questions” section of the book “Cracking the Coding Interview” by Gayle Laakmann McDowell. Within that, I continued my work on Tree data structures. Started trying to replicate the example pretty print functions provided in the article I am reading through. I had to pause working on my Horizontal Pretty Print project to better understand string/character manipulation in the
C
programming language. It is a bit of a detour but I imagine it will pay itself off in the long run. Continued reading theC
programming book called “The C Programming Language” by Brian W. Kernighan and Dennis M. Ritchie. I am currently working through some example programs that utilize character arrays. Right away I realize that I should definitely start defining my utility functions and then place them below themain
function. It might feel better tbh. Although, separating functions into header files might be the best solution as my work gets bigger. - I started reading through chapter 6 of the book “Eloquent JavaScript” by Marjin Haverbeke. I am starting to read the book to help cover some insecurities I have about my knowledge of the language. I learned JavaScript on the fly through projects and YouTube videos. There are some core questions about the language that I don’t think I can answer, so hopefully this will help. I continued reading through Chapter 6. I was mainly re-reading the sections on prototypes, classes, and class notation. I wrote a ton of notes and tested a few different scenarios to answer some of my questions. It was great. I think one more day of revision and this concept will finally sink in. I cannot recommend this chapter enough if you have ever wondered why you can build a class using
function
,class
and expression notation.
JavaScript Notes on Chapter 6
These notes are incomplete so be cautious with the info. Check for yourself LOL.
Prototypes in JavaScript
In addition to a JavaScript object’s set of properties, all objects also have a prototype. A prototype is another object that is used as a fallback source of properties. When an object gets a request for a property that it does not have, its prototype will be searched for the property, then the prototype’s prototype and so on. Ultimately, the ancestor of almost all prototypes is the Object.prototype
console.log(Object.getPrototypeOf({}) == Object.prototype);
// → true
console.log(Object.getPrototypeOf(Object.prototype));
// → null
The prototype relations of JavaScript objects form a tree-shaped structure, and at the root of this structure sits Object.prototype
. It provides a few methods that show up in all objects, such as toString
, which converts an object to a string representation.
Many objects don’t directly have Object.prototype
as their prototype but instead have another object that provides a different set of default properties. Functions derive from Function.prototype
, and arrays derive from Array.prototype
.
So then… Does the Array.prototype
and Function.prototype
derive from the Object.prototype
??? Yes.
console.log(Object.getPrototypeOf(Math.max) == Function.prototype);
// → true
console.log(Object.getPrototypeOf([]) == Array.prototype);
// → true
console.log(Object.getPrototypeOf(Function) == Function.prototype);
// → true
console.log(Object.getPrototypeOf(Function.prototype) == Function.prototype);
// → false
console.log(Object.getPrototypeOf(Function.prototype) == Object.prototype);
// → true
Such a prototype object will itself have a prototype, often Object.prototype
, so that it still indirectly provides methods like toString
.
You can use Object.create()
to build an object with a specific prototype. Here is an example:
let protoRabbit = {
// shorthand syntax for writing a method for an object.
speak(line){
console.log(`The ${this.type} rabbit says '${line}'`);
}
};
let killerRabbit = Object.create(protoRabbit);
killerRabbit.type = "killer";
killerRabbit.speak("SKREEEE!");
// → The killer rabbit says 'SKREEEE!
The “proto” rabbit (protoRabbit
) acts as a container for the properties that are shared by all rabbits. An individual rabbit object, like the killer rabbit (killerRabbit
), contains properties that apply only to itself—in this case its type
—and derives shared properties from its prototype.
Classes in JavaScript
The prototype system in JavaScript can be interpreted as a somewhat informal take on classes
in object-oriented programming. A class defines the shape of a type of object along with what methods and properties it has. An object of that shape would be called an instance of the class.
Prototypes are helpful for defining properties that are shared amongst all instances of a class e.g. methods for the class. Properties that differ per instance need to be stored directly in the objects themselves because of limitations in the language – new versions might rectify this. e.g. (Rabbit type
from the example above).
In JavaScript the fundamental way to produce an instance of a given class is to build an object that derives from the desired prototype i.e. (It has all the methods that should be shared by all instances of the class) and we are able to give it the properties that each instance of this class are meant to have. In older versions of JavaScript the prototype was only capable of holding methods, not properties – hence why these two aspects are performed separately. At the basic level this is what it looks like:
// Prototype type declaration for all Rabbits (Rabbit Class)
let protoRabbit = {
// shorthand syntax for writing a method for an object.
speak(line){
console.log(`The ${this.type} rabbit says '${line}'`);
}
};
// Constructor function to build new Rabbit Objects from
// the Rabbit prototype (class) and setting the unique instance
// properties (e.g. type)
function makeRabbit(type){
let rabbit = Object.create(protoRabbit);
rabbit.type = type;
return rabbit;
}
Question: What would happen if we built an instance from the class before setting the prototype properties we want and then later setting the prototype properties. Would it reflect the old blank prototype or the new one. Basically, I am wondering if prototypes are dynamic and reference one source or if each instance has it’s own copy produced from the environment at the time of it’s construction.
Answer: The prototype of the instance would have access to the updated version of the prototype not the one at the time the object was instantiated from the class. So it would seem that all changes to the prototype (class) will be reflected in all instances of that class (prototype) regardless of the time that the instance was constructed. Here is the example using the example protoRabbit
let coldRabbit = makeRabbit("cold");
console.log(Object.getPrototypeOf(coldRabbit));
// -> { speak: [Function: speak] }
protoRabbit.yell = function yell(line){console.log(`The ${this.type} rabbit yells '${line}'!!`);}
coldRabbit.yell("It's cold outside");
// -> The cold rabbit yells 'It's cold outside'!!
console.log(Object.getPrototypeOf(coldRabbit));
// -> { speak: [Function: speak], yell: [Function: yell] }
Anyways… JavaScript provides a way to make defining this type of function easier. If you put the keyword new
in front of the function call, the function itself will be treated as a constructor. We can then add the prototype (class) properties to the Function prototype itself to ensure all objects produced from this constructor function share the same prototype properties.
function Rabbit(type){
this.type = type;
}
Rabbit.prototype.speak = function(line){
console.log(`The ${this.type} rabbit says '${line}'`);
};
let weirdRabbit = new Rabbit("weird");
Constructors (all functions -> all objects, in fact) automatically get a property named prototype, which by default holds a plain, empty object that ultimately derives from Object.prototype. You can overwrite it with a new object if you want. Or you can add properties to the existing object, as the example does.
By convention, the names of constructors are capitalized so that they can easily be distinguished from other functions.
It is important to understand the distinction between the way a prototype is associated with a constructor (through its prototype property) and the way objects have a prototype (which can be found with Object.getPrototypeOf). The actual prototype of a constructor is Function.prototype
since constructors are functions. Its prototype property holds the prototype used for instances created through it.
Conclusion
That’s all for today. This is my sixth round of the “#100daysofcode” challenge. I will be continuing my work from round five into round six. I am currently working through the book “Cracking the Coding Interview” by Gayle Laakmann McDowell. My goal is to become more familiar with algorithms and data structures. This goal was derived from my goal to better understand operating systems and key programs that I use in the terminal regularly e.g. Git. This goal was in term derived from my desire to better understand the fundamental tools used for coding outside of popular GUIs. This in turn was derived from my desire to be a better back-end developer.
I have no idea if my path is correct but I am walking down this road anyways. Worst case scenario I learn a whole bunch of stuff that will help me out on my own personal projects.