0

The prototype property and inheritance in JavaScript is not clear to me.

I have a function:

function User (name) {
    this.name = name;
}

Questions:

1) Why one of the following is false and the other is true?

User.prototype.hasOwnProperty('name'); // false
User.hasOwnProperty('name'); // true

2) What is de difference between the followings:

User.constructor;
User.prototype.constructor;

3) What happens with the User.constructor and User.prototype.constructor if I override the prototype property like this:

User.prototype = {
    changeName: function(newName) {
        this.name = newName;
    }
};

And what if I override it like this:

User.prototype = {
    constructor: User,
    changeName: function(newName) {
        this.name = newName;
    }
};

4) Is User a function or a prototype or what? The following site refers it as prototype: 'The following example creates a prototype ...' https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor

Thank you very much for your answers.

eightShirt
  • 1,457
  • 2
  • 15
  • 29
Farkas István
  • 504
  • 2
  • 5
  • 15
  • Possible duplicate of [How does JavaScript .prototype work?](http://stackoverflow.com/questions/572897/how-does-javascript-prototype-work) – Evan Davis Nov 03 '15 at 20:05

4 Answers4

0

1) why one of the following is false and the other is true?

User.prototype.hasOwnProperty('name'); // false, A
User.hasOwnProperty('name'); // true, B
  • The prototype object hasn't been given a name property and it doesn't have one by default (as User is not native), so this is false for the prototype.
  • The Constructor User is a Function and you've defined the name of the function as "User". This is set on the function object when it's interpreted.

Are you sure you're not confusing this with (new User('foo')).hasOwnProperty('name'); // true?

This last case, the instance of User has a name property which is "foo", as set by the constructor User.


2) what is de difference between the followings:

User.constructor;
User.prototype.constructor;
  • User.constructor is Function because User is a function.
  • User.prototype.constructor is undefined, but you'd normally reference it back at User. This is what would later be accessed as (new User).constructor; // User

3) what happens with the User.constructor and User.prototype.constructor if I override the prototype [...]

Nothing happens to User.constructor in either case.

As for User.prototype.constructor, it wasn't define previously

  • so remains undefined in the first case
  • is set to User in the second case

Please note that in both of these cases the entire prototype is now pointing at a different Object so existing instances will not see these changes and the previous prototype chain is no longer accessible to new instances.


4) is User a function or a prototype or what?

User is a function and is a constructor. In JavaScript we call certain functions constructors if they will be used to build (construct) instances.


It may be helpful for you to see a more abstract example,

// A function `Foo` which will be our Constructor
function Foo(baz) {
    this.bar = baz;
}

// notice here we have `Foo.name; // "Foo"`

// Setting up reference to the constructor through the prototype
Foo.prototype.constructor = Foo;
// Setting up reference to some other shared property through the prototype
Foo.prototype.fizz = ['buzz'];

And then usage

var foo = new Foo('hello world');
foo.bar; // "hello world" (own)
foo.fizz; // ["buzz"] (inherited)
foo.constructor; // Foo (inherited)

var bar = new Foo();
foo.fizz === bar.fizz; // true, this is the same Object reference - it is shared

Don't be afraid to try things out in your Console!

Paul S.
  • 64,864
  • 9
  • 122
  • 138
0

"Everything" in JS is an object.

So a function is a special type of object and that type of object has a property called name which is why User.hasOwnProperty("name") returns true. It has nothing to do with the property of the User object that same function can create. Try calling it something else and you will see this to be the case.

Any object derives from another object, namely it's prototype. The prototype of a function has a constructor property and __proto__ property but no name property. So Ùser.prototype.hasOwnProperty("name")` should return false

Since all properties of the prototype are derived you can do this User.constructor even though User.hasOwnProperty("constructor") would return false

Rune FS
  • 21,497
  • 7
  • 62
  • 96
0

First you need to understand what a prototype is.

In Javascript, almost everything is an object.


Edit (thanks @Mathletics):

Primitive booleans, numbers, and strings are not objects


When you create an object in Javascript, by default, its prototype will be an Object.

So, if I do:

var obj = {};
console.log(obj.__proto__)

This yields:

Object {}


Pause:

To understand the difference between obj.prototype and obj.__proto__, please, refer to this thread.


The next step is to understand the concept of prototype chaining.

This is how inheritance is structured in Javascript. Basically, a prototype is the "parent" of another object, from which it derives methods and properties.

Imagine a scheme where a Rabbit inherits from Mammal, which inherits from Animal. Representing this in Javascript prototype chain would be like:

(Rabbit) -> (Mammal) -> (Animal) -> (Object) -> null

With code:

function Animal(){}
function Mammal(){}
function Rabbit(){}

Mammal.prototype = new Animal();
Rabit.prototype = new Mammal();

If you are able to understand these concepts, you might find the answers to your questions yourself, but I'll try to make it clearer:

1) why one of the following is false and the other is true?

User.prototype.hasOwnProperty('name'); // false
User.hasOwnProperty('name'); // true

You should read the hasOwnProperty method reference:

Every object descended from Object inherits the hasOwnProperty method. This method can be used to determine whether an object has the specified property as a direct property of that object[...]

This is a way to assure that the property you are looking for is defined within the object itself, not deeper in the prototype chain.

A contrary example would be:

console.log(User.hasOwnProperty('constructor'));

Since the constructor property is defined deeper in the prototype chaing, it is not an "own property" of User object.

In your case, name is a property defined within your User object, but not defined in the context of the global Object.

2) what is de difference between the followings:

User.constructor;
User.prototype.constructor;

The fist like takes the constructor of User, the second takes the constructor of its prototype (in this case, the global Object).

3) what happens with the User.constructor and User.prototype.constructor if I override the prototype property like this:

User.prototype = {
    changeName: function(newName) {
        this.name = newName;
    }
};

Please, read this thread.

TL;DR: when you assing directly to the prototype, you are breaking the prototype chain an creating a new one. In the Rabbit example, if you at some point did:

Rabbit.prototype = {
   // ...
};

Your new prototype chain would be:

(Rabbit) -> (Object) -> null

So, in your first example, User.prototype.constructor would yield:

function Object{}

In your second example, it would yield:

function User(name)

Got it?

4) is User a function or a prototype or what?

User is an object whose prototype is a Function object, whose prototype is a Object object.

Drawing it:

(User) -> (Function) -> (Object) -> null

Hope I've been clear.

Community
  • 1
  • 1
Henrique Barcelos
  • 7,670
  • 1
  • 41
  • 66
  • 1
    If you're gonna go into the weeds, it's important to note that _primitive_ booleans, numbers, and strings are __not__ objects. There are object wrappers for each of them, but they are not, by default, objects. – Evan Davis Nov 03 '15 at 19:53
  • This is what I missed: 'Basically, a prototype ...'. But there is something what I sill don't understand: console.log(User.prototype); // User { } // but this should be Object { } and console.log(User.prototype.constructor); // User(name) but this should be something like Object() because the "parent" thing you explained above. Perfectly works and understandable with your example console.log(Mammal.prototype); // Animal { } gives the result I expect. – Farkas István Nov 04 '15 at 00:02
0

Javascript, unlike other languages (Java, ecc.), isn't class-based, it doesn't provide any way to define a class (actually, the next Javascript, ES6-Harmony, introduces the class keyword but it's just a syntactic sugar on top of prototype inheritance and, at the moment, isn't available in any browser)...

So, Javascript implements the (aka) OOP (Object Oriented Programming) via Prototype Inheritance. If you want to create a custom object, you need to use a function that defines it. Example:

var Person = (function() {
  /**
   * this is the Constructor (if you have in mind a class-based language)
  **/
  function Person() {}
  
  return Person;
})(window);

Doing that we have defined a New Object Person and we can have multiple instances of it using the new operator:

var me = new Person();
var you = new Person();
//...

As all languages do, javascript objects can have Methods and Properties, methods and properties can be both of Instance and Class.

var Person = (function() {
  function Person() {}
      
  /**
   * Static Method
  **/
  Person.sayCiao = function() {};   
      
  /**
   * Static Property
  **/
  Person.ciao = 'Ciao';  
  
  

  /**
   * Instance Method
  **/
  Person.prototype.sayHello = function() {};  

  /**
   * Instance Property
  **/
  Person.prototype.hello = 'Hello';
  
  
  return Person;
})(window);

As you can see (try in your console), using the prototype property we can define methods or properties that all objects created by calling new Person inherit.

1) why one of the following is false and the other is true?

Of course, statics methods or properties don't belong to the instance and hasOwnProperty returns true only when is called using the constructor function. Viceversa, instances methods or properties belong only to their instances and hasOwnProperty returns true only when is called using the new operator. This is the normal behaviour that you can meet in other programming languages.

Note: in ES6 the Function Object has a property name and this is the reason how your test returns true, but isn't referenced to the name property that you define in the Person Constructor (read more).

  1. Example of usage:

var Person = (function() {
  function Person(name) {
    this.firstname = name
  }
  
  Person.prototype.firstname = '';
  
  Person.factory = function(name) {
    return new Person(name);
  };
  
  return Person;
})(window);

var hitmands = Person.factory('Giuseppe');
console.log('you are', hitmands);

var you = Person.factory('BatMan');
console.log('hitmands is', you);

console.info('Person has a name?', Person.hasOwnProperty('firstname'));
console.info('You have a name?', you.hasOwnProperty('firstname'));

The property prototype belongs to the prototype chain, this is the reason how your test return false... ({}).hasOwnProperty('prototype')... You can read more following this link. Simply prototype and what it contains doesn't is own property of your object.

2) what is de difference between the followings (ecc.)

As someone said, one belongs to the function and the other to the prototype property.

3) what happens with the User.constructor and User.prototype.constructor if I override the prototype property like this (ecc.)

You can use that way to extend behaviour from one class to another... Read more about this.

Hitmands
  • 13,491
  • 4
  • 34
  • 69