Search code examples
javascriptprototypecallbindapply

Call/Bind/Apply vs prototype


In the following code:

function User(name) {
    this.name = name;
}

var user = new User('Jason Bourne');

User.prototype.sayHi = function() {
    return 'Hi ' + this.name;
};

var sayHello = function() {
    return 'Hello ' + this.name;
};

Both functions will give me the same result if I bind the object to sayHello (sayHello.bind(user)) or if I use user.sayHi();

So my question is, is there a reason to use one method over the other? I thought I've read somewhere that creating things on prototype is discouraged, if so why?

CORRECTION:

I erroneously wrote Object.prototype.. instead of specifying (Object I create).prototype..


Solution

  • The reason you don't want to use Object.prototype.sayHi = function(){} is that once you do, everything that has Object in its prototype chain will be able to use sayHi. That's the core of prototypical inheritance.

    It's OK to add things to the prototype of objects that you create (and it's just considered bad practice to add to Object.prototype). Just understand that when you do, anything in your objects prototype chain will be able to use that function.

    function sayHello() {
        console.log("hello");
    }
    
    // Bad
    Object.prototype.hello = sayHello;
    Date.hello(); // Prints hello
    

    Call, Apply, and Bind are actually slightly different from adding to prototype and Bind is also different from Call and Apply as well.

    Call and Apply

    Function.call() and Function.apply() use whatever function you are calling or applying at the moment of the call or apply.

    For example, if we wanted to use the forEach() method on a NodeList

    var els = document.querySelectorAll("div");
    Array.prototype.forEach.call(els, function(el){
        el.classList.add("someClass");
    

    The big difference between call and apply is that call takes a variadic argument and apply takes an Array.

    function say() {
        console.log(arguments);
    }
    say.call(this, "a", "b");
    say.apply(this, ["a", "b"]);
    

    Bind

    Using Function.bind() is actually a different thing though. Bind lets you create a context binding where you can call a function from a specific context when you want.

    function honk() {
        console.log(this.sound);
    }
    
    function Car() {
        this.sound = "honk";
    }
    
    function Van(){
        this.sound = "beep";
    }
    var c = new Car();
    var v = new Van();
    
    var ftorCar = honk.bind(c);
    var ftorVan = honk.bind(v);
    
    ftorCar(); // prints honk
    ftorVan(); // prints beep
    

    You can now pass ftorCar around and call it when you want to and it will have the correct scope "binding".