28

I'm trying to get my head around this black art called JavaScript - and, I must admit, pretty excited about it. I've been looking at code examples, mainly from "easeljs" since that is what I will be using mainly. And I'm a bit confused..

I (think I) understand the difference between using the prototype for functions or properties that are class variables and using this.someProp for 'instance' variables (Yes, I understand that there are no classes in JavaScript.)

The code I have looked at, and am using as templates for my own code, declare prototype variables and then refers to them with this i.e.

In the constructor:

this.name = name;

Then a declaration:

Object.prototype.name;

And later,

this.name = "Freddy";

This is within functions called with 'new' so in this case, as I understand it, this refers to the current object. What puzzles me is what the prototype declaration is doing and why do we use it for instance variables?


Clarification: In the following code, I don't see what the prototype declaration of radius is achieving:

(function(){
    // constructor
    function MyCircle(radius){
        this.radius = radius;
    }
    MyCircle.prototype.radius;
    this.area = function(){
        return 3.14*this.radius*this.radius;
    };
    window.MyCircle = MyCircle;
}());
6
  • @jayeshjain not the same question - this one is about declaring "normal values" on the prototype, not functions. Commented May 25, 2013 at 16:03
  • 2
    The line MyCircle.prototype.radius; is not a declaration. It's an anonymous access to an undefined property. It's essentially the same as writing undefined;. Commented May 25, 2013 at 17:28
  • 7
    The line MyCircle.prototype.radius appears to be free of any side-effects and could be removed without altering the behaviour of the code. It might merely be there as an effort to document the property. Commented May 26, 2013 at 11:53
  • 1
    The response from the folks at easeljs is: Prototyping is the proper way to put properties on objects that will be instantiated. Any comments on this? Commented May 28, 2013 at 3:34
  • 1
    @DaveM adding values on the prototype is a good way to add default properties on objects that will be instantiated. It would be interesting to see your question and their response in full. Commented May 29, 2013 at 7:21

4 Answers 4

59

The value on a prototype has a key behaviour that is different from a property set directly on the instance. Try this:

// Create a constructor
function A() {}

// Add a prototype property
A.prototype.name = "Freddy";

// Create two object instances from
// the constructor
var a = new A();
var b = new A();

// Both instances have the property
// that we created on the prototype
console.log(a.name); // Freddy
console.log(b.name); // Freddy

// Now change the property on the
// prototype
A.prototype.name = "George";

// Both instances inherit the change.
// Really they are just reading the
// same property from the prototype
// rather than their own property
console.log(a.name); // George
console.log(b.name); // George

This would not possible without prototypical inheritance.

You can test whether the property is the instances property or the prototype property using the hasOwnProperty method.

console.log(a.hasOwnProperty("name")); // false

An instance can override the prototype value.

b.name = "Chris";
console.log(b.hasOwnProperty("name")); // true
console.log(a.name); // George
console.log(b.name); // Chris

And return to the prototype value.

delete b.name;
console.log(b.hasOwnProperty("name")); // false
console.log(b.name); // George

This is a powerful part of prototypical inheritance.

In the other pattern:

function A() {
  this.name = "George";
}

The this.name variable is declared again with every new instance.

It makes some sense to have methods as functions declared on the prototype. Rather than the function definition being re-declared on every instance, all instances can share a single function.

In terms of variables, rather than functions, the prototype can possibly be used for default values in the case that an instance does not set its own value.

The code in a fiddle

Sign up to request clarification or add additional context in comments.

1 Comment

Yes, I get that. But the code I've been looking at is more like this:
10

A value stored on the prototype provides a default value for that property.

If you subsequently write a value to that property, the instance will acquire that new value, hiding the value that's on the prototype, which will be left intact.

In the context of the code you've now added to the question:

MyCircle.prototype.radius;

does absolutely nothing. It's a no-op - it attempts to read that property and then discards the result.

Comments

0

Yeah, I agree the prototype can be used for default values of properties (variables). The constructor function doesn't need to declare a property; it may be done conditionally.

function Person( name, age ) {
    this.name = name;

    if ( age ) {
        this.age = age;
    }
}

Person.prototype.sayHello = function() {
    console.log( 'My name is ' + this.name + '.' );
};

Person.prototype.sayAge = function() {
    if ( this.age ) {
        console.log( 'I am ' + this.age + ' yrs old!' ); 
    } else {
        console.log( 'I do not know my age!' );
    }
};

Person.prototype.age = 0.7;

//-----------

var person = new Person( 'Lucy' );
console.log( 'person.name', person.name ); // Lucy
console.log( 'person.age', person.age );   // 0.7
person.sayAge();                           // I am 0.7 yrs old!

See how Lucy's age is conditionally declared and initialized.

Comments

0

Other answers have already explained the difference between prototype vs instance properties.

But just to add to the answer, let's break down your code snippet:

(function(){                         // <------- 1
   // constructor
   function MyCircle(radius){        // <------- 2
       this.radius = radius;         // <------- 2.1
   }
   MyCircle.prototype.radius;        // <------- 3
   this.area = function(){           // <------- 4
       return 3.14*this.radius*this.radius;
   };
   window.MyCircle = MyCircle;       // <------- 5
}());
  1. Creating an IIFE which acts as a scope container for the inner code
  2. Declaring a function called MyCircle using a constructor pattern (but observe that it never gets "constructed" so should probably get rid of the capital letter since it's misleading)
    • when invoked creates a radius instance property on the invoked object
  3. Attempting to access a radius property on MyCircle function's prototype which doesn't exist so evaluates to undefined
  4. Creating an area instance property on the global window object and assigning it a function expression
  5. Creating a MyCircle instance property on a window object and assigning to it the MyCircle function

Summary: It seems like it's creating an area and MyCircle properties on the global window object, and when MyCircle is invoked it creates an additional radius property.

Usage: MyCircle should be invoked before area since area relies on MyCircle initialising the radius:

window.MyCircle(10);
window.area(); // evaluates to 314

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.