Use of .apply() with 'new' operator. Is this possible?

后端 未结 30 2717
Happy的楠姐
Happy的楠姐 2020-11-22 00:39

In JavaScript, I want to create an object instance (via the new operator), but pass an arbitrary number of arguments to the constructor. Is this possible?

30条回答
  •  爱一瞬间的悲伤
    2020-11-22 01:11

    Yes we can, javascript is more of prototype inheritance in nature.

    function Actor(name, age){
      this.name = name;
      this.age = age;
    }
    
    Actor.prototype.name = "unknown";
    Actor.prototype.age = "unknown";
    
    Actor.prototype.getName = function() {
        return this.name;
    };
    
    Actor.prototype.getAge = function() {
        return this.age;
    };
    

    when we create an object with "new" then our created object INHERITS getAge(), But if we used apply(...) or call(...) to call Actor, then we are passing an object for "this" but the object we pass WON'T inherit from Actor.prototype

    unless, we directly pass apply or call Actor.prototype but then.... "this" would point to "Actor.prototype" and this.name would write to: Actor.prototype.name. Thus affecting all other objects created with Actor...since we overwrite the prototype rather than the instance

    var rajini = new Actor('Rajinikanth', 31);
    console.log(rajini);
    console.log(rajini.getName());
    console.log(rajini.getAge());
    
    var kamal = new Actor('kamal', 18);
    console.log(kamal);
    console.log(kamal.getName());
    console.log(kamal.getAge());
    

    Let's try with apply

    var vijay = Actor.apply(null, ["pandaram", 33]);
    if (vijay === undefined) {
        console.log("Actor(....) didn't return anything 
               since we didn't call it with new");
    }
    
    var ajith = {};
    Actor.apply(ajith, ['ajith', 25]);
    console.log(ajith); //Object {name: "ajith", age: 25}
    try {
        ajith.getName();
    } catch (E) {
        console.log("Error since we didn't inherit ajith.prototype");
    }
    console.log(Actor.prototype.age); //Unknown
    console.log(Actor.prototype.name); //Unknown
    

    By passing Actor.prototype to Actor.call() as the first argument, when the Actor() function is ran, it executes this.name=name, Since "this" will point to Actor.prototype, this.name=name; means Actor.prototype.name=name;

    var simbhu = Actor.apply(Actor.prototype, ['simbhu', 28]);
    if (simbhu === undefined) {
        console.log("Still undefined since the function didn't return anything.");
    }
    console.log(Actor.prototype.age); //simbhu
    console.log(Actor.prototype.name); //28
    
    var copy = Actor.prototype;
    var dhanush = Actor.apply(copy, ["dhanush", 11]);
    console.log(dhanush);
    console.log("But now we've corrupted Parent.prototype in order to inherit");
    console.log(Actor.prototype.age); //11
    console.log(Actor.prototype.name); //dhanush
    

    Coming back to orginal question how to use new operator with apply, here is my take....

    Function.prototype.new = function(){
        var constructor = this;
        function fn() {return constructor.apply(this, args)}
        var args = Array.prototype.slice.call(arguments);
        fn.prototype = this.prototype;
        return new fn
    };
    
    var thalaivar = Actor.new.apply(Parent, ["Thalaivar", 30]);
    console.log(thalaivar);
    

提交回复
热议问题