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 /

Object types in JavaScript

by Keith Peters

Keith Peters
  • bit-101.com

Content

  • All About instanceof
  • Determining Object Types
  • More About Object Types
  • Where to go from here

Created

9 April 2012

Page tools

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

Requirements

Prerequisite knowledge

Basic knowledge of JavaScript and object creation as covered in JavaScript object creation: Learning to live without "new".

User level

Beginning

In my previous article, JavaScript object creation: Learning to live without "new", I discussed strategies for creation of objects and code reuse. I also encouraged you to learn about and to try out the Object.create method.

The first question that many people have when they try out this method is “How do I get instanceof to work with these objects?” It's a good question that opens up a large enough can of worms to warrant an additional article on the subject.

All About instanceof

First of all, look at what the instanceof operator does and what it tells you. Say that you have a constructor function and you create an object using new with that function:

function Foo() { this.name = "foo"; } var foo = new Foo();

You can now use the instanceof operator, with the instance and a constructor function, to determine if the instance is an “instance of” that constructor function. In other words, to determine if the instance was created using that particular constructor function:

foo instanceof Foo; // true

Now if you have another constructor function Bar, and created an object using that, you could determine that it is not an instance of Foo:

var bar = new Bar(); bar instanceof Foo; // false

What are some uses for this check?

Well for one, because JavaScript is not a strongly typed language you have no way of specifying the type of a function's arguments. So a common use of instanceof is to ensure that the correct type of object was passed:

function handleFoo(obj) { if(obj instanceof Foo) { // do Foo stuff with obj } else { // fail, throw an exception perhaps } }

Another similar use case is manipulating the object depending on what type it is:

function handleObject(obj) { if(obj instanceof Foo) { // do Foo stuff with obj } else if(obj instanceof Bar) { // do Bar stuff with obj } }

What does instanceof actually do? It looks at the prototype of the function passed in and checks to see if is equal to the [[Prototype]] of the specified object. If it’s equal, instanceof returns true. If not, it continues this way on up the object's prototype chain until it gets to Object, in which case it returns false. (Unless, of course, you were checking if an object is an instance of Object: all objects, other than a few built-in types such as numbers and booleans, are instances of Object.)

In the example above, you can see the constructor directly:

console.log(foo.constructor); // logs the Foo function

instanceof searches the entire prototype chain. So, the following would also be true, assuming that you had a SubFoo function that inherited from Foo. (In other words, it had Foo on its prototype chain.)

var subfoo = new SubFoo(); subfoo instanceof Foo; // true, assuming SubFoo inherits from Foo

Now let’s look why instanceof doesn't work with Object.create. First, create the object:

var fooType = { name: "foo"; } var myFoo = Object.create(fooType);

What happens when you use instanceof in this case?

myFoo instanceof fooType;

What happens is that you get a big fat error saying that instanceof was expecting a function and got an object. Since fooType is not a function, you are out of luck. Furthermore, if you check the myFoo constructor property, its constructor is the Object function. Recall from how instanceof works: it returns false when it hits Object on the prototype chain unless you are checking instanceof Object. Thus, myFoo instanceof Object is the only thing that would ever return true here.

So, given the example functions above, handleFoo and handleObject, how would you know what type of object has been passed into those functions?

Well, there are two ways to answer that question. I give you the answer you are probably looking for first. But then, I will ponder whether the question is even the correct one to ask.

Determining Object Types

Other than instanceof, what other tools inspect what kind of things objects are? Here are a few.

typeof

The typeof operator simply returns the JavaScript type of a given object. While typeof has its uses, it is not particularly helpful in the discussion at hand. The typeof operator returns a minimal set of results based on the object you pass to it. In simple terms, given the following objects, it returns the following strings:

Undefined: undefined

Null: object

Boolean: boolean

Number: number

String: string

Function: function

Pretty much everything else: object

In the examples mentioned, this information does not help at all, since anything passed in is probably just an object.

isPrototypeOf

If you are looking for a replacement for instanceof, isPrototypeOf is the closest you are going to find. It basically does exactly what its name says: returns true if one object is the prototype of another object. Like instanceof, it searches the prototype chain until it finds the object it is looking for, or reaches Object, at which point it returns false.

There is one aspect of this method which can be a bit confusing at first. You call isPrototypeOf on the object that is the potential prototype, passing in the object to find its prototype. In other words, if you have an object called myFoo and you wanted to see if it had fooType in its prototype chain, you would type:

fooType.isPrototypeOf(myFoo)

I have often been tempted to use this in the reverse order, calling it on myFoo, passing in fooType. And I've seen others make the same mistake. So be on the lookout for it. Here's an example of isPrototypeOf in use:

var fooType = {}; var barType = Object.create(fooType); var myBar = Object.create(barType); console.log(barType.isPrototypeOf(myBar)); // true console.log(fooType.isPrototypeOf(myBar)); // true

Making instanceof work

Finally, for those of you who really want to use instanceof, what can you do? Well, you can keep coding with new and constructor functions. Or, because JavaScript is quite an expressive language, you can come up with some sort of combination of Object.create and object factory functions that allow instanceof to continue to work. Karl Krukow explains one such system in his blog post JavaScript parasitic inheritance, power constructors and instanceof.

Note, however, that since instanceof requires a function as an argument, you must have functions around in your object creation workflow. You decide whether creating a custom creation function such as in that article is better than just using standard constructor functions.

More About Object Types

Why care about object types?

It seems a bit of a silly and basic question, but I think it's actually one worth asking. After all, if you are going through all this trouble to determine what types are objects are, there had better be a darned good reason, right?

Generally speaking, the reason to know what type of object you have is so that you know what you can do with it:

  • What properties you can read on the object, and what types of values those properties hold.
  • What properties the object expects you to set, and what types of values it makes sense to set them with.
  • What methods you can call, what those methods take as arguments (if any), and what values they return (if any).

If you're expecting an array as an argument to a function, you can push things onto the array, pop things off, slice, splice and sort it. But if it's not an array, you are likely going to wind up with a runtime error when you do most of those things.

Of course, the same is true for custom object types. You'd like to be sure that they are what you think they are before you do what you think you can do with them.

Another common use for type checking in JavaScript is pseudo-function overloading. JavaScript does not support function overloading the way some languages do. But because it makes no requirements on the number or type of arguments passed to a function, overloading is easy to implement at run time. Just execute a different code path depending on what types of arguments were passed in.

Say that you had a shape type that encapsulated a geometric shape. And you have a draw function that can take a shape as an argument. But you also want to be able to pass in an array of points and have it draw those points as a path. You could do something roughly like this simplified example:

function draw(shapeObj) {     if(shape.isPrototypeOf(shapeObj)) {         // draw the shape based on the shape api     }     else if(shapeObj instanceof Array) {         // draw the array of points as a path     } }

A hard, cold look at types in JavaScript

Earlier, I said that I would ponder whether the question of an object's type is even a relevant one. There are a few ways to approach this question.

First of all, what is meant by “type”? In many languages, this indicator would explain what class the object was created from. But let's look back at the typeof operator. As you recall, it returns one of the following for any object: undefined, boolean, number, string, function or object. This is not a failure of the typeof operator, but a reflection of the basic fact that that is a pretty complete list of the types available in JavaScript.

When you create a constructor function, you have not created a new type as you have with a class in a class-based language. You've merely set up a mechanism to create objects with a specific prototype. Even an array is not really an instance of the Array type – because there is no Array type. An array is just an object with a specific prototype – defined in Array.prototype. This object creation with prototyping is why typeof [] returns: "object".

This may sound like semantic trickery, but it's an important concept to understand if you want to really grasp the subject.

But on a more practical basis, you still want to know what an object is, right? Not so fast. Again, why do you want to know what it is? So you know what it does and what you can do with it. That's the key. That's what's important.

I think Christian Johansen said it best in the book, Test Driven JavaScript Development:

“This may sound strange, but instanceof really isn’t helpful in a world in which objects inherit objects. Object.isPrototypeOf helps determine relationships between objects, and in a language with duck typing such as JavaScript, an object’s capabilities are much more interesting than its heritage.” (emphasis added)

Even if you know what constructor function a particular object is an instance of, there's no guarantee that someone else hasn't redefined the functionality of that “type”. Thus, the best way to know if an object does something is to directly check if it does that thing. This brings  us to the subject of “duck typing”.

Duck Typing

Duck typing refers to the duck test, a somewhat humorous statement of reasoning which goes like this:

“If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.”

In terms of code, you can say that if you need an object that has methods x, y, and z; and the object you've been given has those methods; then, it's probably OK for your purposes, regardless of what its constructor or prototype is. On the other hand, if it doesn't have the methods you need, then you don't really care what “type” it claims to be. It's useless to you.

One of the most common duck typing examples in JavaScript is detecting arrays. It's often necessary to ensure that an object passed to a method is an array, so that you can push things into it, iterate over it, and so on. At first glance, this seems pretty simple. Just check:

obj instanceof Array

or:

obj.constructor === Array

And in many cases, those checks work. But not always. One problem occurs if you get an object from another iframe on the page. Because each iframe is in its own sandbox, the Array constructor functions are not equal and the above tests fail.

One of the solutions is duck typing. If the object in question has, for example, a sort function, a join function and a splice function, chances are that it is an array. Juriy Zaytsev (aka: kangax) has a great discussion of the problem and various solutions on his blog Perfection Kills, `instanceof` considered harmful (or how to write a robust `isArray`):

Of course, this article is about objects created through Object.create, so instanceof and constructor checks are not even an option. Say you had a pathType object that allowed you to add and remove points, and render the path to a canvas:

var pathType = {     points: [],     addPoint: function(point) {         this.points.push(point);     },     removePointAt: function(index) {         if(this.points.length > index) {             this.points.splice(index, 1);         }     },     render: function(context) {         context.beginPath();         context.moveTo(this.points[0].x, this.points[0].y);         for(var i = 1; i < this.points.length; i += 1) {             context.lineTo(this.points[i].x, this.points[i].y);         }         context.stroke();     } };

And you made an instance of it with Object.create:

var myPath = Object.create(pathType);

Now, in some other portion of the code, you are passing this path to some method and you want to ensure that this object is indeed a path, because you plan to use it as such. You could write an isPath method that looks like the following code:

function isPath(obj) {     return obj != null &&            typeof obj.addPoint === "function" &&            typeof obj.removePointAt === "function" &&            typeof obj.render === "function"; }

Of course, you could also simply use the code:

function isPath(obj) {     return pathType.isPrototypeOf(obj); }

trusting that nobody messed with the pathType object. But using duck typing allows for a crude form of coding to an interface.

As long as an object implements the methods defined in the first version of the isPath method, it passes the test. Your code assumes it is safe to use that object as a renderable path. It's not failsafe, but if you publish the expected interface, others can code to it.

So, do you want to test for every possible method of an interface? Probably not, especially if you have an object with dozens of methods on its API. One strategy is to check for two or three unique properties or methods that would give you confidence that the object has the correct capabilities. Another concept is to break it down into specific subsets of functionality. Maybe separate an isRenderable function and a hasPointsCollection function rather than a single monolithic isShape function. Again, rather than trying to test the type, you'd be testing specific capabilities if and when you needed them.

Where to go from here

I'm not here to push any methodology down your throat or to say one way of creating objects and later determining their types is superior than any other. I simply hope you have learned a new concept or two that you can use to accomplish what you want in JavaScript.

Again, you might want to look at the following resources:

  • Karl Krukow’s JavaScript parasitic inheritance, power constructors and instanceof
  • Christian Johansen’s Test Driven JavaScript Development
  • Juriy Zaytsev’s `instanceof` considered harmful (or how to write a robust `isArray`)

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
  • JavaScript object creation: Learning to live without "new"
  • Pseudo-classical object-oriented programming in JavaScript with Minion
  • Backbone.js Wine Cellar tutorial – Part 2: CRUD

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