0

When I use JavaScript prototype to inherit a object and want to use it's method in the following way:

var Father = {
  name:'Father',
  act:function(){
    console.log('the name is '+this.name);
  }
}
var Son = function(){
   act();
}
Son.__proto__ = Father;
Son();

This doesn't work, when Js Engine run Son(), it should search act() through it's prototype chain.

But why it only works the following way:

var Father = {
  name:'Father',
  act:function(){
    console.log('the name is '+this.name);
  }
}
var Son = {
  name:'Son'
}
Son.__proto__=Father;
Son.act();
Matt Oestreich
  • 8,219
  • 3
  • 16
  • 41
Bill
  • 167
  • 1
  • 1
  • 8

3 Answers3

1

The long and short of it is the function act() does not exist when you are trying to use it.

Just because you want Son to inherit from Father does not mean JS knows you want to do that. When you are trying to using act() JS has no idea you are wanting to tie Son to Father... as far as JS is concerned they are completely different functions/objects/etc.. and have absolutely ZERO relation for all JS knows.

Again, you need to use an actual act function within the appropriate scope - JS has no clue what your intentions are - how do you expect JS to know which object to pull act() from... What if there was a Mother object with an act method?...

First Snippet: To resolve this, just build an act() function...

var Father = {
  name:'Father',
  act:function(){
    console.log('the name is '+this.name);
  }
}

function act() {
  return this.name;
}

var Son = function(){
   act();
}

Son.__proto__ = Father;
Son.act();

Second Snippet: It's no different than trying:

var Father = {
  name:'Father',
  act:function(){
    console.log('the name is '+this.name);
  }
}

var Son = function(){
  // using 'act();' here is no different than trying:
  somethingThatDoesntExist();
}

Son.__proto__ = Father;

try   { Son();                      } 
catch { console.log("Oh no error\r\n\r\n"); }

// If you don't assign anything..
// It will work... because of inheritence..
Son = {} // MAKING SON AN OBJECT NOT A FUNCTION
Son.__proto__ = Father;
// If you don't change the name, it will log: 'the name is Father'
Son.name = "Son"; 
console.log("Son as an object {} ... we had to do `Son.name = 'Son'` here");
Son.act();
console.log("");

// But if you change Son to be a function, then inherit, you dont have to 
// change the name... 2 completely different things....
Son = function(){}
Son.__proto__ = Father;
console.log("Son as an function(){} ... we DID NOT have to do `Son.name = 'Son'` here since Son.name will be the name of the function, which is Son");
Son.act();

Third Snippet: Or if you did:

var Father = {
  name: 'Father',
  act: function() {
    console.log('the name is ' + this.name);
  }
}

var Son = function() {
  function act() {
    return this.name;
  }
}

Son.__proto__ = Father;
Son.act();

Fourth Snippet Or you can do:

var Father = { 
  name:'Father', 
  act:function(){ 
    console.log('the name is '+this.name); 
  } 
} 

var Son = { 
  name:'Son'
} 

Son.__proto__ = Father; 

Son.act(); 

Fifth Snippet Or..

var Father = { 
  name:'Father', 
  act:function(){ 
    console.log('the name is '+this.name); 
  } 
} 

var Son = { 
  anythingYouWantHere: function() {
    console.log("anythingYouWantHere " + this.name);
  }
} 

try {
  Son.act() // YOU WILL GET AN ERROR HERE
} catch {
  console.log("YOU WILL GET AN ERROR HERE");
}

Son.__proto__ = Father; 

Son.act(); // the name is Father
Son.anythingYouWantHere(); // anythingYouWantHere Father

Son.name = "Son";
Son.act(); // the name is Son
Son.anythingYouWantHere(); // anythingYouWantHere Son

Son.act = function() {
  console.log("I have now changed act! the name is " + this.name);
}

Son.act(); // I have now changed act! the name is Son
Matt Oestreich
  • 8,219
  • 3
  • 16
  • 41
  • 1
    Thank you for your answer. I think my point actually is "could the inherited function be called in side a object/function". So `this` is important, the problem then focuses on how to make `this` point to the object itself. This is exact what your example did. Thank you @Matt! – Bill Dec 29 '19 at 19:33
0

You need to do two things:

1) Write the prototype object of Son, not __proto. For a discussion of the difference, see this question. (TL;DR: prototype is the object set as the source from which the object/function inherits. __proto__ is the resultant prototype chain that is used to look up and resolve references to methods/properties.)

2) Instantiate Son with the new keyword.

var Father = {
  name:'Father',
  act:function(){
    return 'hello';
  }
}
var Son = function(){}
Son.prototype = Father; //<-- prototype, not __proto__
let foo = new Son(); //<-- instantiate with 'new'
foo.act(); //"hello";

With your current code:

var Son = function(){
   act();
}

act() expects a function defined locally in the scope of Son, not one defined on its prototype tree.

Mitya
  • 33,629
  • 9
  • 60
  • 107
  • Elaborating on `__proto__` vs `prototype` will surely help readers. Otherwise this is an incomplete answer. – Matt Oestreich Dec 29 '19 at 17:57
  • Thank you for your answer, but the answer might not be on the key point. To use prototype and new has no difference with just use __proto__. I now believe the key point is dot function, when use dot between two objects `obj.prep`, the Js engine could find along the prototype chain for `prop` – Bill Dec 29 '19 at 18:03
0

act is not any property of an object. it is just a variable that points to a function.

When you try to access a property of an object then only Javascript first check if the property exists in that object or not, if it does not then only it search in its prototype until a prototype is null.

Anshuman Singh
  • 1,134
  • 1
  • 13
  • 21
  • Repeat it again, I now believe the key point is dot function, when use dot between two objects `obj.prep`, the Js engine could find along the prototype chain for prop. that should be what you said. – Bill Dec 29 '19 at 18:19
  • That is still the wrong way to look at it, Bill. It simply was not working because `act()` wasn't defined anywhere. It's as simple as that. – Matt Oestreich Dec 29 '19 at 18:22
  • Sorry, Matt.I don't think so. I tried the following and it works:`var Father = { name:'Father', act:function(){ console.log('the name is '+this.name); } } var Son = { name:'Son', myfunc:function(){ this.act(); } } Son.__proto__=Father; //Son.act(); Son.myfunc();` – Bill Dec 29 '19 at 18:31
  • the key point is still the `.`: `this.act();` this refer to Son and check the prototype chain to find act() – Bill Dec 29 '19 at 18:34
  • Yes of course that works because it's completely different. You're wrapping act in a different function and tying it to 'this'. That's completely different than what you were doing at first. – Matt Oestreich Dec 29 '19 at 18:54
  • @Bill see my updated answer... I really don't think you're understanding how this works.. The reason both `Son.act()` and `Son.myfunc` work is because of inheritence... if you changed it to this, it wouldnt work... `var Father = {name:'Father',act: function() {console.log('the name is '+this.name);}};var Son = function(){myFunc()};Son.__proto__ = Father; Son();` You also changed `Son` from a `function` to an `object`, which matters a ton... That example is not apples to apples in the least bit. – Matt Oestreich Dec 29 '19 at 19:13
  • @Bill see the SECOND snippet in my updated answer.. This shows how making Son an object versus a function is COMPLETELY different!!!! While you may not "think so" - I "know so"... – Matt Oestreich Dec 29 '19 at 19:24