1

I am new to Javascript and confused about the outcomes of the following statements. Could you help clarifying the reason behind each outcome? It would be appreciated if you could also suggest resources that clearly explain the expected behavior in these cases.

function Person(){
   this.a = function(){alert("a")};
}

Person.prototype.b = function(){alert("b")};
Person.c=function(){alert("c")};

var test = new Person();
test.a(); // works
test.b(); // works
test.prototype.b(); //error

Person.prototype.a(); // error (why?)
Person.prototype.b(); //works (why?)

Person.c(); //works

Person();
Person.a(); /* error (Person() call should have set this.a 
               on the Person object just like the c method, 
               why doesn’t it work?) */

Person.b();//error (why?)
John L.
  • 1,825
  • 5
  • 18
  • 45
  • 3
    Only functions have `prototype` object, `test` is an object. `a` is not defined in `Person.prototype`, but `b` is. – Teemu Jun 23 '16 at 18:26
  • Possible duplicate of [Understanding prototypal inheritance in JavaScript](http://stackoverflow.com/questions/892595/understanding-prototypal-inheritance-in-javascript) – Jared Smith Jun 23 '16 at 18:33
  • @JaredSmith you're wrong, the question you linked doesn't deal with static properties vs instance properties. Please remove your comment – weisk Jun 23 '16 at 18:45
  • @frankies His comment does say "Possible". A more constructive approach might be to edit the differences into the question itself so that it is apparent that they are different. – Heretic Monkey Jun 23 '16 at 18:56
  • @frankies I'm kind of coming around to your point of view on that (to the point where I posted an answer) never the less this needs mod attention given the low-quality answers its attracting. – Jared Smith Jun 23 '16 at 19:09

5 Answers5

2

Okay I'll give it a shot. I'm interviewing soon as well so it's good practice :)

function Person(){
   this.a = function(){alert("a")};
}

Person.prototype.b = function(){alert("b")};
Person.c=function(){alert("c")};

var test = new Person();
test.a(); // works
test.b(); // works
test.prototype.b(); //error

Sounds like you got this, but test is an object, not a constructor. It has no prototype key on it.

Person.prototype.a(); // error (why?)
Person.prototype.b(); //works (why?)

Here's where things get fun. Look at the Person() function; all it really does reference the parameters passed to it and returns a new object. Doesn't seem more complicated than that. However, this is where JavaScript's crazy prototypical inheritance comes into play.

Say you wrote a higher-level prototype method on String, like String.prototype.capitalize = function()..., and the method capitalized the string. Every new string you created would have the capitalize() method on it, but it's not like the string is an object with that method key on it.

It's the same here with what Person.prototype.a() and Person.prototype.b() is doing. Running an object through the Person() function creates an object with those keys. Since the Person() constructor only returns an object with a key of a, this is what test looks like so far:

console.log(test); // {a: [Function]}

But why does test.b() work? It's because any object created by a constructor inherits all the properties on that constructors .prototype. Adding something to the prototype doesn't change the keys added to the constructed object but instead gives its constructed objects access to it. Calling a method on something first looks at it's keys, then it's constructor's hidden [[prototype]] value, then it's parent, and so on. You can see this in console.logs in Chrome.

Person();
Person.a(); /* error (Person() call should have set this.a 
               on the Person object just like the c method, 
               why doesn’t it work?) */

Person.b();//error (why?)

Your mistake here is saying that Person() is an object. It's not; it's a function. The this reference in the constructor refers to the object being passed to it; that means the variable it's being set to. Since we are just calling Person() and not setting the result to anything, this is undefined and the result of Person() is undefined as there's nothing to return. A function can't have keys or methods.

Hope I could help. This was good practice for me too!

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
joh04667
  • 7,159
  • 27
  • 34
1

I am of two minds about whether or not this is a duplicate, or even whether it shouldn't be broken up into several different questions. Nevertheless, since this is attracting answers of dubious quality, lets go through your code line by line.

function Person(){
   this.a = function(){alert("a")};
}

Defines the function Person. Nothing special yet. Calling it Person() will, depending on whether or not its running in strict mode, throw an error 'cannot set property "a" of undefined' or it will create a global variable 'a' with the vaue being a function that alerts 'a'.

However, by convention, Capitalized functions in Javascript are supposed to be constructors and called with the new operator. Calling new Person() does some magic for you. It creates a new object and sets it to the this value in the constructor function. The new object is also implicitly returned by the constructor, which is why it has no return statement. Meaning the new person has a method a that alerts 'a' when called.

But this is rarely done in practice, using the prototype is much more common. The new operator also sets the newly created object's internal prototype to be the value of the constructor function's .prototype property (the object doesn't actually get a .prototype property). Anything defined on the constructor .prototype object will be available to every instance created by calling that constructor with new.

Person.prototype.b = function(){alert("b")};

This defines a function b on Person (the constructor function)'s .prototype object. It will be available to all created instances of Person made by calling new Person(). It can also be called directly Person.prototype.b(). This method is better than the one used to attach the 'a' method because all of the Persons share the value of 'b' but all have their own copy of 'a'.

Person.c=function(){alert("c")};

In Javascript everything is an object, including functions. Objects can have properties assigned to them. Here you are assigning a function to the c property of the Person function itself. If you are used to class-based languages, this is similar to a class static method.

Hopefully by now the rest will become clearer. Every Person including 'test' will have an 'a' method because the constructor assigns it. But Person's prototype has no 'a' method, its merely assigned in the constructor. Person's prototype has a 'b' method, meaning all Person instances have access to that shared 'b' method. The Person function itself has a 'c' method, but it isn't passed on to the instances, so 'test' has no 'c' method.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Jared Smith
  • 19,721
  • 5
  • 45
  • 83
0

When you do Person.c = ..., you're setting static properties, thus they are not part of the prototype.

Later on, you are trying to call prototype methods to a constructor, and they don't exist because the prototype is the blueprint for instances of that constructor.

weisk
  • 2,468
  • 1
  • 18
  • 18
  • `this.a` does not create a static property. – Jared Smith Jun 23 '16 at 18:34
  • Care to explain what is it then? – weisk Jun 23 '16 at 18:35
  • Its adding a property to each created instance. `Person.a()` will error. I'm also do not understand how your answer in any way improves on any of the ones in the question I flagged this as a dupe of. – Jared Smith Jun 23 '16 at 18:36
  • Now i figured that you're correct, `a` is not part of the function. But you're still not answering my question. It is programatically setting this 'static-like' property on the constructor. How should we call this kind of property? – weisk Jun 23 '16 at 18:44
  • `this` in a constructor called with `new` refers to the newly created object, it does not and cannot refer to the function itself unless you do some horrific thing like `Person.call(Person)`. Its an object method, one that every Person instance gets its own copy of, and is called (using the above code) `test.a()`. – Jared Smith Jun 23 '16 at 18:57
0

class.prototype is acting like link between objects and your class. class.prototype you can assign functions and properties that will be shared between all instance of your class and when call function will lookup at the prototype object of the class

// so you can call prototype here

Person.prototype.fun;

// but here you directly call the func

test.fun

MDN

0

I will try to explain it you but English is not my primary language.If you have any specific question ask me in the comments section and I will elaborate it more. For a full understanding read more here

test.a(); // works -> Yes because it accessing the property that exists in  Person it self
test.b(); // works ->First It will look into test instance properties if it doesn't find it will look one level up into the Person prototype object and it will find it there.

test.prototype.b(); //error because test is an instance and instances do not have a prototype property.

Person.prototype.a(); // error (why?) Because you are going to look for a property a inside Person prototype which does not have it. Property lookup goes only forward not backward. 
Person.prototype.b(); //works (why?) because b is a property of the Person prototype. 
//typeof Person.prototype is object same as var prototype={} than prototype.b=function(){} so now you can call prototype.b();

Person.c(); //works c is 'static' (more like object literal property assignment because every function in js still is an object) property of Person  same as var Person2={};Person2.c=function(){}; that is why you can access it without needing to initialize Person. 

Person();
Person.a(); /* error (Person() call should have set this.a 
                           on the Person object just like the c method, 
                           why doesn’t it work?) */ That property requires you to create an instance of Person.

Person.b();//error (why?)  it is the same as a but b is a property of prototype of Person
Dynamikus
  • 2,861
  • 4
  • 22
  • 20
  • "*property that exists in Person function*" is wrong or at least very confusing terminology for properties of Person instances – Bergi Jun 23 '16 at 21:22
  • a is a property of Person object/function. Yes every instance of the Person will have that property as well. To make it less confusing I am removing the function and replace it instance. Thnx – Dynamikus Jun 23 '16 at 21:38
  • 1
    `c` is a property of the `Person` function object. `a` is a property of the `test` instance – Bergi Jun 23 '16 at 21:45
  • Yes you are right but let say you do not create an instance of Person. If some one asks you what properties does the Person has?What would be your answer? – Dynamikus Jun 23 '16 at 21:48
  • Depends on whether "Person" refers to the class or the constructor function object. In the first case, `b`, `a` and `static c`, in the second `c`, `prototype` and `name`. – Bergi Jun 23 '16 at 21:54
  • Hmmm a little bit confusing to me. ok thnx – Dynamikus Jun 23 '16 at 22:03