Search code examples
javascriptconstructorprototype

Is it possible to append a method to a constructor/function without prototype property?


function DoIHavePrototype()
{
    var a = 10;
}

CheckIt = new DoIHavePrototype();

DoIHavePrototype.prototype.GetFnName = function()
{
    return "DoIHavePrototype"
}

alert(CheckIt.GetFnName())

In the above code,I observe that prototype is an in-built property for the function using which we can append property/method to a function.

But if I remove the prototype keyword in the above code like the following:

DoIHavePrototype.GetFnName = function()
    {
        return "DoIHavePrototype"
    }

I don't get error in function definition but instead I get error while calling the method alert(CheckIt.GetFnName()) as "CheckIt.GetFnName is not a function"

What does the JS interpreter assume this to be??


Solution

  • In order to be able to invoke some function a method on an object, there are 4 ways to introduce it to the object.

    The first way is what you've done in your original code, which is to assign the function to the object prototype:

    Foo.prototype.myFunc = function () { .... }
    

    Another way is to assign it to this within the constructor.

    function Foo() {
      this.myFunc = function () { .... }
    }
    

    We can also assign it directly to the instance:

    var foo = new Foo();
    var myFunc = function () { .... }
    foo.myFunc = myFunc
    

    Finally, we can bind a function to the instance:

    var foo = new Foo();
    var myFunc = function () { .... }
    var myFuncFoo = myFunc.bind(foo)
    

    The last case is a bit special since we have a function that's not a property of the instance, but behaves like an instance method because it's invocation context is affixed to the instance.

    The most common way of defining instance methods is assignment to the prototype. The prototype property on the constructor is what the instances inherit from, so that's where we put stuff. It's important to keep in mind that the instances inherit from the prototype property, not the constructor function. Assigning anything to a constructor property does not make it available as an instance property.

    Assignment to this can sometimes be used if we want to have a method that's bound. For instance:

    function Foo() {
      this.boundMeth = this.meth.bind(this)
      this.val = "foo"
    }
    
    Foo.prototype.meth = function () { 
      console.log(this.val)
    }
    

    This is useful if we want to pass instance.boundMeth() as a value to another function (e.g., event handler). In JavaScript, unlike many OO languages, methods are unbound:

    // Using Foo from the previous example
    
    function runner(fn) {
      fn()
    }
    var obj = new Foo()
    
    runner(obj.meth)  // Logs `undefined`
    runner(obj.boundMeth) // Logs `foo`
    

    When assigning to the constructor prototype, you can assign in bulk:

    Foo.prototype = {
      meth1: function () { .... },
      meth2: function () { .... },
    }
    

    If you use ES6, you can also use the class keyword:

    class Foo {
      myFunc() { .... }
    }
    

    This is the same as Foo.prototype.myFunc = function () { .... }.