Defining Objects
Function Constructors, new, and The History of JavaScript
There are lots of different ways to construct objects. We know object literals already: {}
. Another way to construct objects is to use function constructors and the new
keyword.
The power of the function constructor comes from the new
keyword, an operator that returns a constructed object. new
is basically syntactic sugar for a series of steps:
new
creates an empty object{}
.Then it invokes the function
Person()
.It changes the
this
reference to that empty object it created.Finally, it runs
Person()
with the newthis
.
Note: If you place a return
inside your function constructor, it overrides the default behaviour of new
!
Function Constructors and '.prototype'
Function constructors automatically set the prototype for you via the prototype
property built into every function object (just like name
).
The prototype
property never gets used until you use the new
keyword. By default the prototype
property is an empty object.
To add properties and methods to the prototype, do this:
The power of a prototype is that every linked object will pull properties and methods from the same reference: FuncConstruct.prototype
. This allows you to add properties and methods on the fly.
Best practice: Properties are typically placed inside the constructor because they vary between objects. But methods are placed in the prototype
.
A major reason to place methods in the prototype
is efficiency. Placing a method in the function constructor means creating new memory space for every single object created, which could be 1000s. On the other hand, having objects all reference the same prototype
for the same method means only needing it in one place in memory.
Dangerous Aside: Functions and 'new'
The JavaScript engine won't throw an error if you forget to add new
because it will just think it's running a basic function instead of a function constructor.
Solution: By convention, capitaize your function constructor, so it's easy to tell what you're dealing with.
Conceptual Aside: Built-in Function Constructors
Built-in function constructors like Number
and String
are where you get access to all properties and methods for different primitives. These properties and methods come from the prototype
object in the function constructor.
Technically, when you call something like "string".length
, the JavaScript engine runs the string through the function constructor to give you access to the length
property.
Note: Numbers aren't automatically converted to a Number object like strings are.
Dangers of built-in function constructors
You generally want to avoid built-in function constructors and opt to use literals instead (unless you absolutely can't avoid it).
This is because comparison and coercion get unintuitive with them:
Note: Built-in function constructors can be treated as regular functions without using new
. This is good for conversion like Number("3")
.
Dangerous Aside: Arrays and for..in
Arrays are objects with indices as the names in their name/value pairs. That means this works:
However, if you add a property to Array.prototype
, be careful that it will get added to the for..in
loop!
Best practice: Use the standard for loop to iterate over an array. for..in
loops can mistakenly iterate down into the prototype chain.
Object.create and Pure Prototypal Inheritance
The use of new
and function constructors was a way to make JavaScript make more sense to developers used to classical inheritance.
The pure prototypal inheritance way to create objects is this:
Polyfill
Polyfill is code that adds features that the engine may lack.
Here's an example polyfill for Object.create
:
ES6 and Classes
Classes were introduced in ES6. However, they aren't templates/definitions like we're used to in other languages. Classes are still objects: they're objects that are used to create other objects!
They still have properties and methods like constructor
.
To set the __proto__
of an object, just use extends
and super
:
Note: super
basically calls the constructor of its prototype!
Last updated