0

I started to code in Javascript early this year. I am having hard time figuring out some of Javascript key concepts, especially the prototypal inheritance. I learned from Douglas Crockford's book that if you augment Function.prototype, you can make a method available to all functions. And, there comes this code...

Function.prototype.method = function (name, func) {
    this.prototype[name] = func;
    return this;
};

I tested the following code from the book and it works.

String.method('trim',function(){
    return this.replace(/^\s+|\s+$/g, '');
});

console.log('"'+'    neat    '.trim() + '"');

Then, I tried to create a custom function and augment a method to it.

function Foo()
{
};

Foo.method('test', function() {
    return "This is a test!";
});

console.log(Foo.test());

actually, I tried console.log different combinations Foo, test(), proto, etc., but I just couldn't get "This is a test!" printed out. Could anyone help?

Victor Gau
  • 191
  • 2
  • 11
  • 1
    I'm not sure if DC is a good source to learn about JavaScript prototype. He complains about not having private variables for encapsulation but then completely ignores incapsulation by modifying objects he doesn't own (Function, Object, String ...) reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain#Bad_practice.3A_Extension_of_native_prototypes I have seen him state that Parent constructor cannot be re used and create an instance of Parent to set prototype of Child. – HMR Sep 01 '14 at 04:13
  • The following answer explains about constructor functions, prototype and their purpose (DC would call is 'classical inheritance'): http://stackoverflow.com/a/16063711/1641941 I gave up listening to Crockford about 'classical inheritance' after seeing this: https://www.youtube.com/watch?v=ya4UHuXNygM (first comment states what's wrong with it) But he repeats the wrong information in books and articles. – HMR Sep 01 '14 at 04:16

3 Answers3

1

Actually "string" is an instance of String class. So just create an instance of your class and it should work.

function Foo()
{
};

Foo.method('test', function() {
    return "This is a test!";
});

console.log(new Foo().test());
Daniel Aranda
  • 6,426
  • 2
  • 21
  • 28
  • 2
    There are no classes in ECMAScript. – RobG Sep 01 '14 at 03:33
  • 1
    @RobG class are emulated through function definitions. "new Foo()" is an instance of Foo – Daniel Aranda Sep 01 '14 at 03:35
  • I was trying to figure out the relationship among objects in this picture (https://www.byvoid.com/upload/wp/2012/04/prototype-1024x702.png). It seems to me that Function.prototype is not in the prototype chain of foo (i.e., new Foo()). Are there any mistakes in the picture? Thanks! – Victor Gau Sep 01 '14 at 04:01
  • @user2629723 I believe the root of your doubts is... "Foo.prototype" belongs to the object "Foo", however your book does not use Foo.prototype for add "trim", it uses a function wrapper that they named "method", and there, they create a new prototype method for the "current instance" of that object not to the object itself. "method" define to instances by using "this.prototype" instead of "Foo.prototype", I believe your book uses that technique as it is helpful for inheritance. I do not like to critic others work, but does not seems to be the best book to learn JS. – Daniel Aranda Sep 01 '14 at 04:18
0

trim() is a method of String.prototype already in modern versions of Javascript so not a great example to try out. Skip the extra step and prototype Function yourself:

Function.prototype.test = function(){
    return "This is a test!";
}

function Foo(){
}

console.log(Foo.test());
// logs "This is a test!"
James L.
  • 4,032
  • 1
  • 15
  • 15
0

There is a difference between how you're calling your method in your String example versus your Foo example. In the String example, you're calling it on an instance of String:

'    neat    '.trim()

whereas you're calling it on the class function Foo:

Foo.test()

Check out the explanation of the prototype chain at Mozilla. This is going to sound weird, because it always confuses people, but the prototype is not the [[Prototype]]. When Javascript looks for inherited properties, it looks at the [[Prototype]], which gets assigned on object creation. If you want to set the [[Prototype]] for instances of a class, you set the prototype property on the constructor Function. This is how I think about it:

function Foo() {};
Foo.prototype = {...};
// note:
//   Foo.prototype == {...}
//   Foo.[[Prototype]] == Function.prototype
var foo = new Foo();
// note:
//   foo.prototype is undefined
//   foo.[[Prototype]] == Foo.prototype
ldgabbay
  • 1,133
  • 8
  • 9