Help differentiating between constructors and objects and functions

I believe I am confusing myself the more I try to differentiate these different code blocks:

function Bird() {
  this.name = "Albert";
  this.color = "blue";
  this.numLegs = 2;
}

var Bird = function(){
  this.name = "Albert";
  this.color = "blue";
  this.numLegs = 2;
}

var Bird = function(name, color, numLegs) {
  this.name = name;
  this.color = color;
  this.numLegs = numLegs;
};

var bird = {
  name: "Albert",
  color: "blue",
  numLegs: 2,
};

Can someone help me understand the differences (and perhaps side effects) when using one method versus another of these to accomplish the same thing, even though they may be subtle at times.

This is a constructor. You are initialiting a object with the this reference, without the return of an ordinary function. Recall, a constructor is a function to create a object in combination of new.

Similarly to #1, the difference: anonymous syntax of function assined to variable Bird.

This is a syntax of anonymous function as #2, but the constructor is receiving arguments arity > 0. The new objects are initialited to this arguments.

This is a simple object. It is neither builder nor function.

1 Like

The first are Constructors. Not to confuse you with a bunch of fancy jargon, but the first function you wrote will be available to any code on the page, the second will however only be available to the code below it. This is because of Javascript’s Hoisting mechanic. The third is also a constructor function, except the values for the declared fields can now be instantiated when the constructor is called with the “new” keyword. The last one is an object literal. The object literal is not like the others. Its mechanics are not like the functional constructor declaration. Constructors are used when you want to create many “types” of a object…and the literal when you want to create only one type of a object and perhaps just vary what methods and properties it has. This is a very intresting topic. Check MDN

1 Like

The first three are effectively exactly the same, with the third being the most useful, as it let’s you set what the three properties are.

JavaScript does not really support what people coming from other popular Object-oriented languages call classes (even though it has a class construct that looks the same). It just has functions, and you return objects from those functions. And when those functions are used in combination with the new keyword (new Bird('Albert', 'blue', 2), you call the functions constructors, and the object that pops out gets some extra stuff added to it to help you identify it as the product of that function (eg it’ll be a type of Bird rather than just a generic Object).

So the fourth example is basically what the end product of one of those functions looks like.

1 Like

There are a lot of conventions in JS that confuses beginners, particularly in your code:
A. “Bird is capitalized - meaning it’s serious stuff!!!”. In reality, it’s just a variable name for your function, like any other variable
B. “This is not just a function, this is CONSTRUCTOR!!!”. In reality, it’s just a function like any other function.
Now, the interesting part. If invoked by itself it will create 3 global variables (as variables are properties of this - in my case, Window object). Try:

function Bird() {
  this.name = "Albert";
  this.color = "blue";
  this.numLegs = 2;
}
Bird();
console.log(name) // "Albert"
console.log(color) // "blue"
console.log(numLegs) // 2

But then, I can also tell any function what is this like this:

const obj = {};
Bird.call(obj);
// Call Bird function substituting this keyword with obj

console.log(obj) // { name: "Albert", color: "blue", numLegs: 2 }

Now comes new keyword. By using new you tell JS:
STEP 1: create a new object that would inherit prototype of function that comes after new keyword. This can be recreated manually like this:

const coolObj = Object.create(Bird.prototype);

console.log(coolObj) // Wow! Bird Object!!!

STEP 2: call function on newly created object:

Bird.call(coolObj)

console.log(coolObj)

in order to make things easier to remember you can just use new Bird and it will do all of that for you on the background.

I can only add to answers on top that it would make HUGE difference if you would use ES6 arrow function to implement that. It won’t work, arrow functions cannot be constructors, as they do not have prototype property and therefore STEP 1 will never happen.

3 Likes

I am really thankful for all of what has been brought to light so far! I knew basically what was being accomplished in these code blocks, but I also knew enough coming from Java that these different code blocks are sure to call different methods behind the scenes, and that it is always beneficial to understand and utilize the differences when it can help you.

Case in point the fact that:

This is exactly the type of things I was looking for. Going through the challenges lately, it feels like I have 1000 questions swirling through my head (ie. should I use this way or that way, and I wonder what the advantage is to using that way.) Thank you all for bringing this very useful knowledge to my attention. I really enjoy learning these things, and I will be digging into all of what everyone has wrote so far!

1 Like

I remember watching this video like half a year ago and wanted to learn what’s the deal with OOP.

It’s pretty good and fairly short. He talks mostly about object primitives which probably isn’t too helpful and moves on to constructors about halfway through, so feel free to skip to that point.

1 Like

I was watching this video, JavaScript and Inheritance from Khan Academy and noticed the var Variable = function(){} notation and really got me thinking about all of this.
LearnWebCode
’s example in the second half of the video you reference really helped.

Thanks, Gigusek, for helping me bridge the gap from my understanding of classes from Java OOP to what JavaScript utilizes.

Thank you for writing it out like that, it’s really helpful. Now I feel like I’m starting to understand what’s actually happening with constructors.

If I’m understanding right, the execution of these two lines are exactly equivalent to:

const coolObj = new Bird();

Also, in regards to arrow functions and impossibility of using like a constructor, iiiked brought up prototype and I read up on this here. Pranav Jindal makes the point that when you make a new Object, it

inherently gets a reference of prototype of Object, which is pointed to by the __proto__ of the newly created object.

Does anyone know if something similar to this __proto__ system of pointing, chaining, or referencing is implemented going forward since it is deprecated per MDN web docs? It seemed like a great way, especially for someone new to JavaScript prototypes to trace back what is happening when dealing with Objects and Functions.

Both videos were recorded years ago when “var” was still a thing, you don’t want to use it anymore. Basically as far as declaring variables goes, I recommend following the rule of “if you can’t use const, use let” :stuck_out_tongue:

1 Like

Not exactly actually, the correct way would be to assign variable to function just like you do with new:

let coolObj = Object.create(Bird.prototype);

coolObj = Bird.call(coolObj);

…or you can do it in one line if you want to use const:

const coolObj = Bird.call(Object.create(Bird.prototype));

You can test it on built-in constructors as well:

const arr = Array.call(Object.create(Array.prototype));
1 Like

Thanks iiiked. It is always great to know it is not just some round about way of accomplishing the same thing, and that it does not produce other unintended side effects!

Also, something I noticed based on tinkering in dev tools: it looks like in functions (e.g. Bird) constructor is set to same function call. So, constructor of Bird is Bird(). So, when we did
const coolObj = Object.create(Bird.prototype);
coolObj got a reference to Bird() in its prototype. So instead of doing Bird.call(coolObj) we can do coolObj.constructor(). As far as I can tell, at least, both result in the same thing.

1 Like

Considering that coolObj.constructor is Bird, they are absolutely the same, in either way you call Bird on coolObj

1 Like

I’ve also found this article: https://codeburst.io/master-javascript-prototypes-inheritance-d0a9a5a75c4e?gi=4dd82c2866c1

This is the best explanation of JS inheritance I’ve seen so far, including stuff we discussed here. Absolutely must read!

1 Like

Thanks iiiked, you’re absolutely right this was a great read and helped my understanding!

Can you comment on __proto__ that is heavily referenced in the article?

Per the MDN page:

This feature has been removed from the Web standards.

__proto__ gives you direct access to the prototype properties, that’s where the reference is stored on any given object - like if you create an instance of a Bird object, it’ll have a property called __proto__ where the references to all those prototype methods are. It’s just how JS works, there has to be a property somewhere on a given object that allows you to use prototype methods.

Just don’t access/modify it directly (as it says in the article and everywhere else). It will, amongst other things, generally make code very slow because manipulating it directly is reimplementing what the JS engine itself does automatically.

Yes DanCouper, I believe I understand the functionality of __proto__.

My question, however, is: what is __proto__ being replaced with, and/or how to understand looking up the prototype chaining going forward, since __proto__

has been removed from the Web standards.

says the MDN page itself?

It’s being removed from web standards, but it’ll still be there if that is the way a browser vendor decides they want to implement prototypes. It’s just an attempt to get people to stop using it directly. You generally cannot remove stuff completely from the web platform without breaking the internet, but in this case it was only added because some engines exposed it, so as a temporary measure it was standardised for backwards compatibility. It should be a possible implementation detail in the underlying engine code, not a way to access the underlying runtime

The question is, why would saying “there is a hidden property on each object that references the prototype that you cannot access directly” not fine, why do you feel you need __proto__ available?