FIRST: Nearly everything in Javascript is an object. Almost all of it. Variables, functions, everything. But Object Oriented Programming is a way of thinking, not a type of language. You can orient your JavaScript programming around the objects with methods, prototypes, messages, etc... or ignore objects and do function based sequential programming. You can also do object oriented programming in languages that don't have objects (although it can be quite difficult and may not be worth the effort). The orientation doesn't depend on the language, but languages that support objects nicely are really nice. JavaScript supports object oriented programming; it does NOT require it, nor is it a true Object Oriented language. JavaScript is flexible.
Also:
Programming is first seen as writing a list of instructions. Like a recipe or assembly instructions for a toy or furniture. Once we start actually writing programs, we pretty quickly see the need for variables; labeled or "named" boxes to store data which we act upon with the instructions.
Then we see that the data is every bit as important as the instructions. Maybe it isn't a set of instructions that changes data, but data that learns to change via sets of instructions? It is simply a shift in point of view.
Often, the data is a model of something in the physical world. The application we are writing is keeping track of real world things. Cars, or cards, or cannons. As we model those things in the computer, it feels natural to focus on the objects as collections of attributes, along with programs that define their behavior. Car.color = "red". Car.fuel=10%, Car.start(), Car.turn(20), Car.accelerate(10), Car.speed?, etc...
Another area where this makes sense is when we have many data types and need a different program to work on each different type. For example, if we need to find the square root of an integer (whole number, nothing right of the decimal point), the program we write to do that is much shorter and simpler than the one we need to find the square root of a floating point number. So should we have a different name for each program; sqrt_int, sqrt_float, etc... or should we teach each data type how to find it's own square root? 123->sqrt, 123.45->sqrt. We ask the data, or rather the object (a collection of related data and methods), to perform an operation on an attribute of itself.
JavaScript makes objects easy by allowing us to put variables inside other object type variables. And variables can contain programs, as well as numbers, strings, and other objects. However, "primitive objects", like strings or numbers can't be assigned new attributes; they can only be assigned new values. They have "hard-coded" attributes like their value, length, or methods. JavaScript doesn't call these "primitive" variables objects, although they really are, the word "object" is used for objects you can add things to.
Note that these primitive values are parts of object classes, which can still have methods. For example:
var myvar = 123+"4" myvar.length //tells us how long the value in myvar is. This is actually an attribute. myvar.toString //contains a program (class method) that will convert myvars value to a string. myvar.toString() //gives us the result of calling that program; the value as a stringIt's critical to understand the difference between .toString, which is the method, and .toString() which is a call to execute that method.
Methods: If you have a function inside an Object, we call it a "Method". It's a nice way of organizing things; all the stuff related to the object is in the object: Data, Functions, other objects, everything. The methods (functions in the object) can even be used to change things inside the object that we can't otherwise change; variables which are out of scope. This can be really good because the methods can check the changes we ask for and make sure they are valid. For example, Arrays know how to sort their elements.
The curly brackets "{}" are used to initialize these (like the quote marks around a string, or the [] around an array) and the "dot" syntax is used to access those elements or add new ones. Inside the {} we can use labels, followed my a colon ":" and values after that to setup attributes. So we can collect up all the attributes and programs that define an object under one label:
let my_car = { color: "red", paint: function(color) {this.color = color} //1 } my_car.speed = 90
In this simple example, my_car.color is "red" and if we enter my_car.paint("green") then my_car.color will become "green". We can add new attributes by just using a new name after the dot. e.g. my_car.speed = 90 adds a new attribute called speed, and sets its value to 90.
Note that despite also using { }, objects do NOT use the statement block syntax which also uses { }. E.g. you can not do { var count = 0 } in an object declaration. It would be { count: 0 } instead.
Exercise: Think about some object in the real world and write a JavaScript object for it. Have at least one attribute and method which acts upon that attribute. Test it to make sure it works.
One advantage to being able to put named variables inside objects is that we can re-use names. Image we want to keep track of Cars and Planes. Each can have a color. We could use variables named car_color and plane_color or we could make a Car object and a Plane object, each with a variable called color inside, but Car.color and Plane.color are now 2 different things, despite having the same name.
To put it another way, quoting C. Fry of MIT: "A namespace is a context whereby in THIS context "foo" means 2 but in this OTHER context, "foo" can mean 3. English has words with multiple meanings and we (humans) figure out which meaning is relevant by the context. When you're in a supermarket, "produce" means fruit and vegetables, but in a factory "produce" is not a noun, its a verb for making (the things the factory makes)."
Note that methods as well as data can have the same name and still work differently:
let model_t = { color: "black", paint: function(color) {this.color = "black"} //1, 2 year_introduced: 1908 }
Notice that model_t seems to have a great deal in common with Car.
Exercise: What color is model_t after model_t.paint("blue")? Why is that from a programming and a historical perspective?
Exercise: Make another object which is a type of your first object, or make an object that your first object is a type of. Be sure there is a more generic, and a more specific, object. For example, you might have an object for the generic "rock" and the specific "flint". Make some of the attributes the same between the two objects, but give them different values, and add more attributes to the more specific object.
In the car object, the paint method takes a parameter called color and sets the objects color to color. Notice the scope issue there. Which color is color? The parameter or the attribute? The keyword "this" makes all the difference. this.color is the attribute, because this is another name for car. Inside car any mention of this is exactly the same as mentioning car. The keyword this is the JavaScript equivalent of saying "hey you" when you can't remember someones name.
Why not just say car.color = color? Well, because we can use the same function as a method in multiple objects. So if we want to add a new method, we can define a function, and assign it to both car and model_t, and it will work in either one. For example:
function get_dirty() { this.color = "dirty " + this.color } car.get_dirty = get_dirty model_t.get_dirty = get_dirty
Notice we don't have () after get_dirty here. We aren't calling the function, just setting it's value, which is it's definition; it's code. Now car.get_dirty() will change car.color to "dirty red" and model_t.get_dirty() will change model_t.color to "dirty black", even though it's the same function.
Remember, just like in English, "this" allows us to refer to whatever is here, without naming it.
You are saying exactly the same thing, but the result is different because what you are holding changes. "This" means whatever you are building at the moment. And not having to know the exact name of the thing you are build means that you can build many things, with a Constructor function. When you call the constructor, you can pass in arguments, which become the parameters of the new object that you build. They can become the values of the new objects attributes or they could decide which prototype methods it is assigned or change how those methods work. Because Javascript isn't a pure object oriented language, you can still just define a function, or you can modify an object without making a new constructor. Javascript is flexible.
Exercise: Add a method to both of your objects which modfies a common attribute in some way.
Prototypes: Special objects which are templates for making objects
with the
new keyword.
By convention, these "prototypical" objects are named with a single capital
letter followed by lowercase, and the objects created from them are all lower
case. The document object has a prototype called Document. A more useful
example is
let my_array = new Array.
Any methods or attributes in the prototype are automatically available to the newly created object. This is really nice as it keeps you from having to add all the same stuff over and over. This is how JavaScript does "Classes"; prototyping via constructor functions.
Immutable primitives have mutable prototypes. e.g. Number.prototype
has all the methods for working with numbers, and String.prototype
for strings. You can teach primitives new tricks by adding them there, although
it's probably not a good idea just because it will confuse people. It's called
"Class Augmentation". E.g. You can teach numbers to square root themselves
with:
Number.prototype.sqrt = function() {return Math.sqrt(this)}
and then type in (123).sqrt() which sends the message "square root
yourself" via the method "sqrt" to the number (123). You must put it in
parentheses because otherwise JavaScript thinks you are entering a fraction
when you press the dot. E.g. it thinks you are typing something like 123.45
and when it gets to the "s" it gets confused.
To build a prototype, we need a "constructor function" which we call, but with new.
For example, we can make a new car prototype function:
function Car(color) { this.color = color this.paint = function(color) {this.color = color} } let car = new Car("red") let model_t = new Car("black") model_t.paint = function(color) {this.color = "black"}
Arrays in Javascript are just objects with some special prototype methods for doing array type things like join, slice, or sort, as well as object sorts of things like for...in.
See also: