0

I have been trying to create my own Javascript function, and then add methods using Prototype

So I create a function:

function createObject(){
    this.value = 0;
}

And then I create the Prototype Method:

createObject.prototype.once = function(){
       return this.value+1
};

Then I create the instance of the object:

var x = createObject();

Then, when I try to run x.once() I get:

Uncaught TypeError: Cannot read property 'once' of undefined
at <anonymous>:1:2

And I have no idea why.

Joshua Kleveter
  • 1,769
  • 17
  • 23
Grant Herman
  • 923
  • 2
  • 13
  • 29
  • 1
    `var x = new createObject();` to instantiate an object instead of just calling the function – tklg Feb 26 '17 at 04:32
  • If you intend to use a function as a constructor, it's standard practice to capitalize the function's name, so that you will remember to use the `new` keyword. There's some more good practices associated with the pattern [at this question](http://stackoverflow.com/a/383503/5743988). – 4castle Feb 26 '17 at 04:37
  • you should think of a better name for the object, because the name `createObject` actually makes the function sound like a function that creates an object - which you would expect to call without the `new` keyword - this doesn't address your problem, but it's probably something to keep in mind – Jaromanda X Feb 26 '17 at 04:43
  • Constructors are PascalCase (not camelCase) by convention; help people remember to use `new` (ignoring error-checking) by following it! – Ry- Feb 26 '17 at 06:32

3 Answers3

2

You could find this error by placing a breakpoint on the this.value = 0; line, and examining this; you will find that it is not what you expect.

The most robust solution is to rewrite your constructor to make sure it's being called with new, using new.target:

function CreateObject() {
  if (!new.target) throw new TypeError('CreateObject() must be called with new');

  this.value = 0;
}

const object = CreateObject();

Linters can help you find this type of error as well. For example, eslint has the new-cap option. It will complain if you call a non-capitalized function with new, or call a capitalized function without new. To take advantage of this, you'll have to follow the convention of capitalizing constructors, as in CreateObject.

TypeScript (or ES6 as well) would report an error if you used class and tried to instantiate it without new:

class CreateObject {
  value = 0;

  once() { return this.value = 0; }
}

var x = CreateObject();

Value of type 'typeof CreateObject' is not callable. Did you mean to include 'new'?

  • 1
    ES6 classes will throw if you try to construct them without `new`, too (re: TypeScript). – Ry- Feb 26 '17 at 06:59
1

You'll need to use var x = new createObject().

In short, the new keyword is what sets up the prototype chain and this bindings within the object that your function returns to x.

I'd recommend that you take a look at the MDN page for more details.

Joshua Kleveter
  • 1,769
  • 17
  • 23
1

When you make instance of class, you have to use new keyword, before class name.

var x = new createObject();

The new operator creates an instance of a user-defined object type or of one of the built-in object types that has a constructor function.

For more information MDN

4castle
  • 32,613
  • 11
  • 69
  • 106
Emran
  • 188
  • 1
  • 12