Adobe
Products
Acrobat
Creative Cloud
Creative Suite
Digital Marketing Suite
Digital Publishing Suite
Elements
Photoshop
Touch Apps
Student and Teacher Editions
More products
Solutions
Digital marketing
Digital media
Education
Financial services
Government
Web Experience Management
More solutions
Learning Help Downloads Company
Buy
Home use for personal and home office
Education for students, educators, and staff
Business for small and medium businesses
Licensing programs for businesses, schools, and government
Special offers
Search
 
Info Sign in
Welcome,
My cart
My orders My Adobe
My Adobe
My orders
My information
My preferences
My products and services
Sign out
Why sign in? Sign in to manage your account and access trial downloads, product extensions, community areas, and more.
Adobe
Products Sections Buy   Search  
Solutions Company
Help Learning
Sign in Sign out My orders My Adobe
Preorder Estimated Availability Date. Your credit card will not be charged until the product is shipped. Estimated availability date is subject to change. Preorder Estimated Availability Date. Your credit card will not be charged until the product is ready to download. Estimated availability date is subject to change.
Qty:
Purchase requires verification of academic eligibility
Subtotal
Review and Checkout
Adobe Developer Connection / HTML5, CSS3, and JavaScript /

JavaScript object creation: Learning to live without "new"

by Keith Peters

Keith Peters
  • bit-101.com

Content

  • Object creation basics
  • Creating particles using Object.create
  • Where to go from here

Created

27 February 2012

Page tools

Share on Facebook
Share on Twitter
Share on LinkedIn
Bookmark
Print
HTML5 inheritance JavaScript

Requirements

User level

Beginning

Sample files

  • Object creation sample file

In this article, I'm going to discuss object creation in JavaScript using prototypal inheritance as an alternative to the new operator.

One significant aspect of JavaScript is that there is rarely a single right way to do any particular task. JavaScript is a loosely-typed, dynamic, and expressive language, which means that there are usually many different ways to accomplish the same task. I'm not saying that the methods described here to create objects are the only correct ways to do so or even the best ways, but I do feel that they are closer to the true nature of the language and will help you to understand what's going on under the covers if you choose to use other methods.

To help you better understand these concepts, this article describes the creation of a basic particle system with multiple rendering targets. This is a complex enough task to represent a real world test of the concepts I'll be demonstrating, rather than a simple hello world type of application.

Object creation basics

The crux of this article is the creation of JavaScript objects. Most tutorials you see will tell you to create a constructor function, add methods to the function's prototype property, and then use the new operator like so:

function Foo() { this.name = "foo"; } Foo.prototype.sayHello = function() { alert("hello from " + this.name); }; var myFoo = new Foo(); myFoo.sayHello();

The newly created object now has all the properties that were defined on the constructor function's prototype. This creates something that looks much like a class in a class-based language. To make a new "subclass" that inherits from that "class", you'd set the prototype property of the "subclass" to a new instance of the original "class". (I'm using quotation marks here because the entities are not actual classes or subclasses.)

function Bar() { } Bar.prototype = new Foo(); Bar.prototype.sayGoodbye = function() { alert("goodbye from " + this.name); } var myBar = new Bar(); myBar.sayHello(); myBar.sayGoodbye();

The problem is that because this structure looks so similar to real classes in other languages, people start expecting it to behave exactly like real classes behave in other languages. But the more you work with these types of "classes", the more you see that they don't behave that way at all. So people get upset with JavaScript, and start thinking it is bad language that can't be used for anything serious. Others go about trying to fix these class-like structures, tacking on various bits of functionality and building up very complex frameworks to get constructor functions and prototypes to look and behave more and more like classes.

Personally, I see this as a bit of a misguided effort. It's not necessarily wrong, but the energy being spent would likely produce better results if it was in another direction.

Embracing prototypal inheritance

JavaScript is not a class-based language, but a prototype-based one. Code reuse is done not by making class templates that are used to instantiate objects, but by creating new objects directly, and then making other new objects based on existing ones. The existing object is assigned as the prototype of the new object and then new behavior can be added to the new object. It's quite an elegant system and it's beautifully implemented in the Io language, which I encourage you to look into.

Before going any further, I want to clarify the term prototype. First, there is the prototype property of a constructor function as shown in the last section's example. There is another hidden property that is the actual prototype of an object. This can be very confusing. The ECMAScript proposal refers to this hidden property as [[Prototype]] . This is exposed in some JavaScript environments as the __proto__ property, but this is not a standard part of the language and should not be counted on. When you create a new object using new with a constructor function, that new object's [[Prototype]] is set with a reference to the constructor function's prototype.

In addition to this naming confusion, there were two design decisions made in the language that have added to the confusion ever since. First, due to the concern that some developers might not be comfortable with prototypal inheritance, constructor functions and the new operator were introduced. Second, there was no direct native way to create a new object with another object as its [[Prototype]] , except through the new operator with a constructor function.

Fortunately, most browsers now support the Object.create method. This method takes an existing object as a parameter. It returns a new object that has the existing object assigned as its [[Prototype]] . Even more fortunately, this method is quite easy to create for those environments that do not support it:

if(typeof Object.create !== "function") { Object.create = function (o) { function F() {} F.prototype = o; return new F(); }; }

So, how would you rewrite the earlier example using Object.create ? First you create a foo object that has a name property and a sayHello function:

var foo = { name: "foo", sayHello: function() { alert("hello from " + this.name); } }; foo.sayHello();

Then, you use Object.create to make a bar object that has foo as its prototype, and add a sayGoodbye function to it:

var bar = Object.create(foo); bar.sayGoodbye = function() { alert("goodbye from " + this.name); } bar.sayHello(); bar.sayGoodbye();

It's also very common to create an extend function that simplifies the adding of methods and properties to the new object. The following method simply copies over any properties from props onto obj :

function extend(obj, props) { for(prop in props) { if(props.hasOwnProperty(prop)) { obj[prop] = props[prop]; } } }

This enables you to create bar like so:

var bar = Object.create(foo); extend(bar, { sayGoodbye: function() { alert("goodbye from " + this.name); } });

Not such a big deal here, but it simplifies things greatly when you are adding several more properties or methods.

OK, now that you have the basics down, you can start putting them together in a real world scenario.

Creating particles using Object.create

The particles used in the example project are going to be very basic: black dots that move around in a two-dimensional space and bounce off the walls. They also support gravity and friction as needed. You'll define a particle object that has all the properties and methods it needs, and place it in an adc object to avoid polluting the global namespace. For more information on namespaces, see the Wikipedia article on unobtrusive Javascript.

var adc = adc || {}; adc.particle = { x: 0, y: 0, vx: 0, vy: 0, gravity: 0.0, bounce: -0.9, friction: 1.0, bounds: null, color: "#000000", context: null, update: function() { this.vy += this.gravity; this.x += this.vx; this.y += this.vy; this.vx *= this.friction; this.vy *= this.friction; if(this.x < this.bounds.x1) { this.x = this.bounds.x1; this.vx *= this.bounce; } else if(this.x > this.bounds.x2) { this.x = this.bounds.x2; this.vx *= this.bounce; } if(this.y < this.bounds.y1) { this.y = this.bounds.y1; this.vy *= this.bounce; } else if(this.y > this.bounds.y2) { this.y = this.bounds.y2; this.vy *= this.bounce; } }, render: function() { if(this.context === null) { throw new Error("context needs to be set on particle"); } this.context.fillStyle = this.color; this.context.fillRect(this.x - 1.5, this.y - 1.5, 3, 3); } };

Next, you'll need a particle system to keep track of all the particles and handle updating and rendering them.

var adc = adc || {}; adc.particleSystem = { particles: [], addParticle: function(particle) { this.particles.push(particle); }, update: function() { var i, numParticles = this.particles.length; for(i = 0; i < numParticles; i += 1) { this.particles[i].update(); } }, render: function() { var i, numParticles = this.particles.length; for(i = 0; i < numParticles; i += 1) { this.particles[i].render(); } } };

And finally, you'll need a main file that creates the system, creates and adds all the particles, and sets up the animation loop.

(function() { if (typeof Object.create !== "function") { Object.create = function (o) { function F() {} F.prototype = o; return new F(); }; } var system, numParticles, canvas, context, bounds; function initSystem() { system = Object.create(adc.particleSystem); numParticles = 200; canvas = document.getElementById("canvas"); context = canvas.getContext("2d"); canvas.width = window.innerWidth; canvas.height = window.innerHeight; bounds = { x1: 0, y1: 0, x2: canvas.width, y2: canvas.height }; } function initParticles() { var i, particle; for(i = 0; i < numParticles; i += 1) { particle = Object.create(adc.particle); particle.bounds = bounds; particle.context = context; particle.x = Math.random() * bounds.x2; particle.y = Math.random() * bounds.y2; particle.vx = Math.random() * 10 - 5; particle.vy = Math.random() * 10 - 5; system.addParticle(particle); } } function animate() { context.clearRect(bounds.x1, bounds.y1, bounds.x2, bounds.y2); system.update(); system.render(); } initSystem(); initParticles(); setInterval(animate, 1000 / 60); }());

The code in this file is contained in an immediately invoked function expression, again to avoid global namespace pollution. (For more information on immediately invoked function expressions, see Ben Alman's blog about the topic. It includes the Object.create shim for browsers that might need it. This is all pulled together in the following HTML file:

<!DOCTYPE html> <html> <head> <title>Particles v1</title> <style type="text/css"> .html, body { margin: 0; padding: 0; } </style> </head> <body> <div> <canvas id="canvas"/> </div> <script type="text/javascript" src="v1/particle.js"></script> <script type="text/javascript" src="v1/particleSystem.js"></script> <script type="text/javascript" src="v1/main.js"></script> </body> </html>

The important lines, for the purposes of this article, are those that create the particle system:

system = Object.create(adc.particleSystem);

and that create the particles themselves:

particle = Object.create(adc.particle); particle.bounds = bounds; particle.context = context; particle.x = Math.random() * bounds.x2; particle.y = Math.random() * bounds.y2; particle.vx = Math.random() * 10 - 5; particle.vy = Math.random() * 10 - 5;

You haven't implemented any kind of extend function yet, but you can see here where it would be useful – calling extend a single time, rather than line after line of assigning properties. In the next iteration, you'll add that and then some.

Adding extend and init

For the second version of the particle system, rather than having the main file create and extend each and every particle by itself, it would be better to have the particles know how to create, extend, and initialize themselves. To support that, you can use two new functions, extend and init , which are added to adc.particle :

var adc = adc || {}; adc.particle = { x: 0, y: 0, vx: 0, vy: 0, gravity: 0.0, bounce: -0.9, friction: 1.0, bounds: null, color: "#000000", context: null, extend: function(props) { var prop, obj; obj = Object.create(this); for(prop in props) { if(props.hasOwnProperty(prop)) { obj[prop] = props[prop]; } } return obj; }, init: function() { this.x = Math.random() * this.bounds.x2; this.y = Math.random() * this.bounds.y2; this.vx = Math.random() * 10 - 5; this.vy = Math.random() * 10 - 5; }, // … // rest of methods are the same as version 1 };

The extend method takes care of creating a new object, passing this as a parameter to Object.create . Thus, it makes a copy of itself. It then takes any properties that were passed into extend , copies them onto the new object it created, and finally returns the new object.

Now, rather than calling Object.create(adc.particle) and setting and tweaking property after property, you can call adc.particle.extend , passing in an object with the properties you want to set, and then call init on the newly created particle.

When you add the extend method to the particle system, the main file becomes a bit simpler. In initSystem , you call adc.particleSystem.extend() to create the new system. You don't need to add any properties to the system, so extend is called with no parameters. Not much of a change there:

function initSystem() { system = adc.particleSystem.extend(); numParticles = 200; canvas = document.getElementById("canvas"); context = canvas.getContext("2d"); canvas.width = window.innerWidth; canvas.height = window.innerHeight; bounds = { x1: 0, y1: 0, x2: canvas.width, y2: canvas.height }; }

In the initParticles method, though, you see an improvement:

function initParticles() { var i, particle; for(i = 0; i < numParticles; i += 1) { particle = adc.particle.extend({ bounds: bounds, context: context }); particle.init(); system.addParticle(particle); } }

Now you can call adc.particle.extend to create each particle, passing in an object that contains the bounds and context , which are then copied to each particle. Finally, you just call init on the new particle, which takes care of randomly setting up its position and velocity. This version works exactly the same as the last, but the creation of individual particles has been greatly simplified.

Adding inheritance

The third version of the particle system supports inheritance. This is key to code reuse. You have one type of object and you want to make another type of object that is slightly different. You don't want to completely recreate the first object with just a couple of changes.

Code reuse has two important benefits. First, there is less code to write. You certainly don't want to write the same code twice. You also don't want to copy and paste code, as this can lead to things getting out of sync, with a function implemented one way over here and the same function implemented a bit differently over there. The second benefit is better performance. When you have the same code duplicated in your live application, it takes longer to download, eats up more memory, and can cause your code to be slower, particularly in object instantiation (because it is instantiating the same code again and again).

The particle system currently renders to an HTML5 canvas. Now, you may want to make a different particle type that renders itself as a DOM object. Ideally, almost all of the particle code would be reused, with only the render method differing. So, with great confidence, you can just take particle.js and remove the render method from it.

Next, make two new files, canvasParticle.js and comParticle.js. The canvas version will be similar to what you've just done:

var adc = adc || {}; adc.canvasParticle = adc.particle.extend({ render: function() { if(this.context === null) { throw new Error("context needs to be set on particle"); } this.context.fillStyle = this.color; this.context.fillRect(this.x - 1.5, this.y - 1.5, 3, 3); } });

This code is quite simple. You just call adc.particle.extend , passing in an object that contains your old render method. This will create a new object that has particle as its [[Prototype]] , and render as a new method directly on the object.

Next you'll have to change main.js a bit to allow for your new object types. Create a mainCanvas.js file for setting up the canvas-based particles. It will only differ in one line, where it uses the adc.canvasParticle type to instantiate particles, rather than just adc.particle :

function initParticles() { var i, particle; for(i = 0; i < numParticles; i += 1) { particle = adc.canvasParticle.extend({ bounds: bounds, context: context }); particle.init(); system.addParticle(particle); } }

The particleSystem.js file can remain unchanged, but of course the HTML file will have to reflect new source files you've created. This example should function identically to the first two versions.

Now you're ready to create the DOM version

The domParticle.js file will be almost as simple as canvasParticle.js. It assumes that there is an element it can position, and positions it using style properties:

adc.domParticle = adc.particle.extend({ render: function() { if(this.element === null) { throw new Error("element needs to be set on particle"); } this.element.style.left = this.x; this.element.style.top = this.y; } });

But in this example, the HTML file and main.js file will need to change significantly. In addition to referencing different source files, the HTML file can eliminate the canvas element and add a container div in which to put all the particle elements:

<html> <head> <title>Particles v3</title> <style type="text/css"> .html, body { margin: 0; padding: 0; overflow: hidden; } </style> </head> <body> <div id="container"> </div> <script type="text/javascript" src="v3/particle.js"></script> <script type="text/javascript" src="v3/domParticle.js"></script> <script type="text/javascript" src="v3/particleSystem.js"></script> <script type="text/javascript" src="v3/mainDom.js"></script> </body> </html>

The main.js file will become mainDom.js and will obviously need to change a bit to create domParticles and give them individual elements instead of references to the canvas's context.

(function() { var system, numParticles, container, bounds; function createElement() { var el = document.createElement("div"); el.style.position = "absolute"; el.style.width = 3; el.style.height = 3; el.style.backgroundColor = "#000000"; container.appendChild(el); return el; } function initSystem() { system = adc.particleSystem.extend(); numParticles = 200; container = document.getElementById("container"); bounds = { x1: 0, y1: 0, x2: window.innerWidth, y2: window.innerHeight }; } function initParticles() { var i, particle; for(i = 0; i < numParticles; i += 1) { particle = adc.domParticle.extend({ bounds: bounds, element: createElement() }); particle.init(); system.addParticle(particle); } } function animate() { system.update(); system.render(); } initSystem(); initParticles(); setInterval(animate, 1000 / 60); }());

This makes use of a new function, createElement , that simply creates a div , styles it, and adds it to the container div . This is what the particle will position when its render method is called.

This final example should be nearly identical to all the other versions. Of course, there are lots of optimization and enhancements that you can do to improve all of these examples. I purposely kept it simple to better illustrate the inheritance aspect.

Where to go from here

You may still prefer constructor functions and the new operator. I'm not going to twist your arm about it. I personally find this method of object creation to be very clean and in accord with the basic prototypal nature of JavaScript.

I encourage you to explore the source code provided in the sample files for this tutorial and try out the particle system in a browser that supports HTML5.

As your needs for more complex apps grow, you can add features onto this basic setup far more cleanly than you can with an pseudo-class based system. For more information, see the following resources:

  • Douglas Crockford's Prototypal Inheritance in JavaScript
  • Douglas Crockford's Classical Inheritance in JavaScript
  • WOODY2SHOES's 005 JSJ Javascript Objects

Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License+Adobe Commercial Rights

This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. Permissions beyond the scope of this license, pertaining to the examples of code included within this work are available at Adobe.

More Like This

  • Introducing the HTML5 storage APIs
  • Introducing theexpressiveweb.com beta
  • Adobe, standards, and HTML5
  • Developing HTML5 games with Impact JavaScript game engine and Dreamweaver CS5.5
  • Using the Geolocation API
  • CSS3 basics
  • Real-time data exchange in HTML5 with WebSockets
  • Pseudo-classical object-oriented programming in JavaScript with Minion
  • Object types in JavaScript
  • Backbone.js Wine Cellar tutorial – Part 1: Getting started

Products

  • Acrobat
  • Creative Cloud
  • Creative Suite
  • Digital Marketing Suite
  • Digital Publishing Suite
  • Elements
  • Mobile Apps
  • Photoshop
  • Touch Apps
  • Student and Teacher Editions

Solutions

  • Digital marketing
  • Digital media
  • Web Experience Management

Industries

  • Education
  • Financial services
  • Government

Help

  • Product help centers
  • Orders and returns
  • Downloading and installing
  • My Adobe

Learning

  • Adobe Developer Connection
  • Adobe TV
  • Training and certification
  • Forums
  • Design Center

Ways to buy

  • For personal and home office
  • For students, educators, and staff
  • For small and medium businesses
  • For businesses, schools, and government
  • Special offers

Downloads

  • Adobe Reader
  • Adobe Flash Player
  • Adobe AIR
  • Adobe Shockwave Player

Company

  • News room
  • Partner programs
  • Corporate social responsibility
  • Career opportunities
  • Investor Relations
  • Events
  • Legal
  • Security
  • Contact Adobe
Choose your region United States (Change)
Choose your region Close

North America

Europe, Middle East and Africa

Asia Pacific

  • Canada - English
  • Canada - Français
  • Latinoamérica
  • México
  • United States

South America

  • Brasil
  • Africa - English
  • Österreich - Deutsch
  • Belgium - English
  • Belgique - Français
  • België - Nederlands
  • България
  • Hrvatska
  • Česká republika
  • Danmark
  • Eastern Europe - English
  • Eesti
  • Suomi
  • France
  • Deutschland
  • Magyarország
  • Ireland
  • Israel - English
  • ישראל - עברית
  • Italia
  • Latvija
  • Lietuva
  • Luxembourg - Deutsch
  • Luxembourg - English
  • Luxembourg - Français
  • الشرق الأوسط وشمال أفريقيا - اللغة العربية
  • Middle East and North Africa - English
  • Moyen-Orient et Afrique du Nord - Français
  • Nederland
  • Norge
  • Polska
  • Portugal
  • România
  • Россия
  • Srbija
  • Slovensko
  • Slovenija
  • España
  • Sverige
  • Schweiz - Deutsch
  • Suisse - Français
  • Svizzera - Italiano
  • Türkiye
  • Україна
  • United Kingdom
  • Australia
  • 中国
  • 中國香港特別行政區
  • Hong Kong S.A.R. of China
  • India - English
  • 日本
  • 한국
  • New Zealand
  • 台灣

Southeast Asia

  • Includes Indonesia, Malaysia, Philippines, Singapore, Thailand, and Vietnam - English

Copyright © 2012 Adobe Systems Incorporated. All rights reserved.

Terms of Use | Privacy Policy and Cookies (Updated)

Ad Choices

Reviewed by TRUSTe: site privacy statement