0
function Ninja(){
  this.swung = true;
}

var ninjaA = new Ninja();
var ninjaB = new Ninja();

Ninja.prototype.swing = function(){
  this.swung = false;
  return this;
};
console.log(ninjaA.swung,"checking Ninja's Swung member")//returning true WHY??
log( ninjaA.swing().swung, "Verify that the swing method exists and returns an instance." ); //false
log( !ninjaB.swing().swung, "and that it works on all Ninja instances." ); //true

If i manipulate a property inside prototype, then i can access it only through prototype. As i am doing ninja.swing().swung - the poperty value has changed using ninja.prototype.swing, but why do i get true when i am doing ninjaA.swung ?

Mohammad Faizan khan
  • 1,213
  • 3
  • 17
  • 32

2 Answers2

0

Not sure what you're expecting to happen but swung is an instance specific member that you manipulate through a shared member using the special this variable.

Even if you define swung on Ninja.prototype it would be true by default but invoking this.swung=false would not change Ninja.prototype.swung because assignment causes swung to be created on the instance instead of looking up the prototype chain.

So if you would like to change a shared member through an instance and have it reflect the changes throughout all instances you'll have to mutate a shared member. You can do for example:

function Ninja(){
    // you want swung to be shared
    // instance specific members are defined here
//  this.swung = true;
}
Ninja.prototype.shared = {swung:true};
var ninjaA = new Ninja();
var ninjaB = new Ninja();

Ninja.prototype.swing = function(){
  this.shared.swung = false;
  return this;
};
console.log(ninjaB.shared.swung);//=true
ninjaA.swing();
console.log(ninjaB.shared.swung);//=false

The following answer explains this in more detail: https://stackoverflow.com/a/16063711/1641941 The part explaining mutating shared members from the prototype from the link above: Constructor function introduction

You can use a function as a constructor to create objects, if the constructor function is named Person then the object(s) created with that constructor are instances of Person.

var Person = function(name){
  this.name = name;
};
Person.prototype.walk=function(){
  this.step().step().step();
};
var bob = new Person("Bob");

Person is the constructor function. When you create an instance using Person you have to use the new keyword:

var bob = new Person("Bob");console.log(bob.name);//=Bob
var ben = new Person("Ben");console.log(ben.name);//=Ben

The property/member name is instance specific, it's different for bob and ben

The member walk is part of Person.prototype and is shared for all instances bob and ben are instances of Person so they share the walk member (bob.walk===ben.walk).

bob.walk();ben.walk();

Because walk() could not be found on bob directly JavaScript will look for it in the Person.prototype as this is the constructor of bob. If it can't be found there it'll look on Object.prototype. This is called the prototype chain. The prototype part of inheritance is done by lengthening this chain; for example bob => Employee.prototype => Person.prototype => Object.prototype (more on inheritance later).

Even though bob, ben and all other created Person instances share walk the function will behave differently per instance because in the walk function it uses this. The value of this will be the invoking object; for now let's say it's the current instance so for bob.walk() "this" will be bob. (more on "this" and the invoking object later).

If ben was waiting for a red light and and bob was at a green light; then you'll invoke walk() on both ben and bob obviously something different would happen to ben and bob.

Shadowing members happens when we do something like ben.walk=22, even though bob and ben share walk the assignment of 22 to ben.walk will not affect bob.walk. This is because that statement will create a member called walk on ben directly and assign it a value of 22. There will be 2 different walk members: ben.walk and Person.prototype.walk.

When asking for bob.walk you'll get the Person.prototype.walk function because walk could not be found on bob. Asking for ben.walk however will get you the value 22 because the member walk has been created on ben and since JavaScript found walk on ben it will not look in the Person.prototype.

More about prototype

An object can inherit from another object through the use if prototype. You can set the prototype of any object with any other object using Object.create. In the constructor function introduction we have seen that if a member can't be found on the object then JavaScript will look in the prototpe chain for it.

In previous part we have seen that re assignment of members that come from an instance's prototype (ben.walk) will shadow that member (create walk on ben rather than changing Person.prototype.walk).

What if we don't re assign but mutate the member? Mutating is (for example) changing sub properties of an Object or invoking functions that will change the object's value. For example:

var a = [];
a.push(11);
a[1]=22;

The following code demonstrates the difference between prototype members and instance members by mutating members.

var person = {
  name:"default",//immutable so can be used as default
  sayName:function(){
    console.log("Hello, I am "+this.name);
  },
  food:[]//not immutable, should be instance specific
         //  not suitable as prototype member
};
var ben = Object.create(person);
ben.name = "Ben";
var bob = Object.create(person);
console.log(bob.name);//=default, setting ben.name shadowed the member
                      //  so bob.name is actually person.name
ben.food.push("Hamburger");
console.log(bob.food);//=["Hamburger"], mutating a shared member on the
// prototype affects all instances as it changes person.food
console.log(person.food);//=["Hamburger"]

The code above shows that ben and bob share members from person. There is only one person, it is set as bob's and ben's prototype (person is used as the first object in the prototype chain to look up requested members that don't exist on the instance). The problem with the above code is that bob and ben should have their own food member. This is where the constructor function comes in. It is used to create instance specific members. You could also pass arguments to it to set values of these instance specific members.

The next code shows another way to implement the constructor function, syntax is different but the idea is the same:

  1. Define an object that has members that will be same for many instances (person is a blueprint for bob and ben and can be for jilly, marie, clair ...)
  2. Define instance specific members that should be unique for instances (bob and ben).
  3. Create an instance running the code in step 2.

With constructor functions you'll set the prototype in step 2 in the following code we set the prototype in step 3.

In this code I have removed name from prototype as well as food because you are most likely going to shadow this almost immediately when creating an instance anyway. Name is now an instance specific member with a default value set in the constructor function. Becaus the food member is also moved from prototype to instance specific member it will not affect bob.food when adding food to ben.

var person = {
  sayName:function(){
    console.log("Hello, I am "+this.name);
  },
  //need to run the constructor function when creating
  //  an instance to make sure the instance has
  //  instance specific members
  constructor:function(name){
    this.name = name || "default";
    this.food = [];
    return this;
  }
};
var ben = Object.create(person).constructor("Ben");
var bob = Object.create(person).constructor("Bob");
console.log(bob.name);//="Bob"
ben.food.push("Hamburger");
console.log(bob.food);//=[]

You may come across similar patterns that are more robust to help with object creation and object definition.

Community
  • 1
  • 1
HMR
  • 37,593
  • 24
  • 91
  • 160
  • i am expecting this if i write this [console.log(ninjaA.swung,"checking Ninja's Swung member")] then i should show me false cause i have changed this property by calling a method which is inside of prototype as you can see in my question – Mohammad Faizan khan Feb 28 '14 at 04:21
  • @MohammadFaizankhan I'd check out the link in my answer. Assigning instance members with values does not affect the prototype. Mutating members of an instance that come from the prototype does affect the prototype. Examples are given in the link posted but I'll copy and paste it in my answer. – HMR Feb 28 '14 at 04:28
0
function Ninja(){
  this.swung = true;
}
var ninjaA = new Ninja();
…
console.log(ninjaA.swung,"checking Ninja's Swung member")

returning true WHY??

Because that's how you initialized it in the constructor.

Then you call .swing(), which sets swung to false (a little counterintuitive, but never mind). After that, you log false as expected.

It works for your ninjaB equally, though you have inverted the logging (.swung == false but you log ! ninjaB.swung).

Bergi
  • 630,263
  • 148
  • 957
  • 1,375