Understanding "Prototypes" in JavaScript

For the purposes of this post, I will be talking about JavaScript objects using syntax defined in ECMAScript 5.1. The basic semantics existed in Edition 3, but they were not well exposed.

A Whole New Object

In JavaScript, objects are pairs of keys and values (in Ruby, this structure is called a Hash; in Python, it's called a dictionary). For example, if I wanted to describe my name, I could have an object with two keys: would point to "Yehuda" and would point to "Katz". Keys in a JavaScript object are Strings.

To create the simplest new object in JavaScript, you can use :

Why didn't we just use ? Stick with me! To look up a value in the object by key, use bracket notation. If there is no value for the key in question, JavaScript will return .

If the String is a valid identifier[1], you can use the dot form:

Adding values

So now you have an empty object. Not that useful, eh? Before we can add some properties, we need to understand what a property (what the spec calls a "named data property") looks like in JavaScript.

Obviously, a property has a name and a value. In addition, a property can be enumerable, configurable and writable. If a value is enumerable, it will show up when enumerating over an object using a loop. If a property is writable, you can replace it. If a property is configurable, you can delete it or change its other attributes.

In general, when we create a new property, we will want it to be enumerable, configurable, and writable. In fact, prior to ECMAScript 5, that was the only kind of property a user could create directly.

We can add a property to an object using . Let's add a first name and last name to our empty object:

Obviously, this is extremely verbose. We can make it a bit less verbose by eliminating the common defaults:

Still, this is pretty ugly to create a simple property list. Before we can get to a prettier solution, we will need to add another weapon to our JavaScript object arsenal.

Prototypes

So far, we've talked about objects as simple pairs of keys and values. In fact, JavaScript objects also have one additional attribute: a pointer to another object. We call this pointer the object's prototype. If you try to look up a key on an object and it is not found, JavaScript will look for it in the prototype. It will follow the "prototype chain" until it sees a value. In that case, it returns .

You'll recall that we created a new object by invoking . The parameter tells JavaScript what it should set as the Object's prototype. You can look up an object's prototype by using :

We can also add functions that we share across many objects this way:

Setting Properties

Since creating a new writable, configurable, enumerable property is pretty common, JavaScript makes it easy to do so using assignment syntax. Let's update the previous example using assignment instead of :

Just like when looking up properties, if the property you are defining is an identifier, you can use dot syntax instead of bracket syntax. For instance, you could say in the example above.

Object Literals

Still, having to set a number of properties every time can get annoying. JavaScript provides a literal syntax for creating an object and assigning properties to it at one time.

This syntax is approximately sugar for:

The most important thing about the expanded form is that object literals always set the newly created object's prototype to an object located at . Internally, the object literal looks like this:

 

The default dictionary comes with a number of the methods we have come to expect objects to contain, and through the magic of the prototype chain, all new objects created as object literal will contain these properties. Of course, objects can happily override them by defining the properties directly. Most commonly, developers will override the method:

This is especially useful because a number of internal coercion operations use a supplied method.

Unfortunately, this literal syntax only works if we are willing to make the new object's prototype . This eliminates the benefits we saw earlier of sharing properties using the prototype. In many cases, the convenience of the simple object literal outweighs this loss. In other cases, you will want a simple way to create a new object with a particular prototype. I'll explain it right afterward:

Let's deconstruct the method. The goal of this method is to create a new object with a set of properties, but with a particular prototype. First, we will use to create a new empty object, and assign the prototype we specify. Next, we will enumerate all of the properties in the object that we supplied, and copy them over to the new object.

Remember that when you create an object literal, like the ones we are passing in to , it will always have as its prototype. By default, the properties that JavaScript includes on are not enumerable, so we don't have to worry about showing up in our loop. However, since is an object like any other object, anyone can define a new property on it, which may (and probably would) be marked enumerable.

As a result, while we are looping through the properties on the object we passed in, we want to restrict our copying to properties that were defined on the object itself, and not found on the prototype. JavaScript includes a method called on to check whether a property was defined on the object itself. Since object literals will always have as their prototype, you can use it in this manner.

The object we created in the example above looks like this:

 

Native Object Orientation

At this point, it should be obvious that prototypes can be used to inherit functionality, much like traditional object oriented languages. To facilitate using it in this manner, JavaScript provides a operator.

In order to facilitate object oriented programming, JavaScript allows you to use a Function object as a combination of a prototype to use for the new object and a constructor function to invoke:

Here, we have a single Function object that is both a constructor function and an object to use as the prototype of new objects. Let's implement a function that will create new instances from this object:

The operator in JavaScript essentially does this work, providing a syntax familiar to those comfortable with traditional object oriented languages:

In essence, a JavaScript "class" is just a Function object that serves as a constructor plus an attached prototype object. I mentioned before that earlier versions of JavaScript did not have . Since it is so useful, people often created something like it using the operator:

I really love that ECMAScript 5 and newer versions have begun to expose internal aspects of the implementation, like allowing you to directly define non-enumerable properties or define objects directly using the prototype chain.

要查看或添加评论,请登录

Goverdhan K.的更多文章

  • Actively looking for a job as UI Architect

    Actively looking for a job as UI Architect

    I am a UI architect and a full-stack developer with architect-level experience of designing and developing web and…

  • Job or Business

    Job or Business

    "If you put Bananas and Money in front of Monkeys, monkeys will choose Bananas because monkeys do not know that money…

  • Type

    Type

    Typos are the JavaScript death by a thousand cuts. At the very least, you should probably be using a tool like ESLint…

    1 条评论
  • Handling Errors in Node.js

    Handling Errors in Node.js

    Error handling is a pain, and it's easy to get by for a long time in Node.js without dealing with many errors correctly.

    3 条评论
  • How to name your Business...

    How to name your Business...

    What's in a name? A lot, when it comes to small-business success. The right name can make your company the talk of the…

    1 条评论

社区洞察

其他会员也浏览了