Creating objects in JS without OOP constructs

Hello i am trying to understand how objects are created in JS.Therefore i am trying to create the following class with plain JS.(I know i can't reinforce types) ,just placed them there as a reference.

Desired behaviour

class User{
    name:String;
    age:number;
    function StateCredentials(){
        return "Name:"+this.name+"\r\n"+"Age:"+this.age;
    }
}

I did not understand the order in which you attach the the prototype to the current object and when do you call apply on it.Also where should the instance method be placed.

Current Implementation

User=(function(age,name){
    function User(name,age){
        this.name=name;
        this.age=age;
        this.credentials=SetCredentials;
    }
    function StateCredentials(){
        return "Name:"+this.name+"\r\n"+"Age:"+this.age;
    }
    x={};
    x.__proto__= User.prototype; 
    User.apply(x,[a]); 
    return x;
});

Call:

function createObject(){
    u=User(3,3);
    u.StateCredentials();
}

Error: Uncaught TypeError: Cannot read property 'StateCredentials' of undefined

As a last note i have seen an implementation where an anonymous method is the trigger that encloses the constructor logic.

(function(){...})(arugments);

3 answers

  • answered 2018-11-08 07:28 Felix Kling

    There are a couple of issues with your code:

    • The User function doesn't return anything. That's why u is undefined and you get that error. You'd have to add return x;
    • Even with that, the call u.StateCredentials(); would fail because you are never creating a property StateCredentials on x. The closest you are ding is creating the property credentials, so you could do u.credentials().
    • You still wouldn't see anything though because you are not doing anything with the return value. You could do console.log(u.credentials()).

    Overall I'm not quite sure what you are trying to achieve. Ignoring that your class example is syntactically incorrect, classes are "plain JavaScript". The syntax is officially part of the language since 2015.

    I feel like different people have a different understanding of what "OPP constructs" really are, so here are a couple of examples.

    No class syntax (constructor function + prototype)

    class is more or less just syntactic sugar. Under the hood we deal with normal constructor functions. So if you are asking how the equivalent pre-class syntax example looks like, it would be something like this:

    function User(name, age) {
      this.name = name;
      this.age = age;
    }
    
    User.prototype.StateCredentials = function() {
     return "Name:"+this.name+"\r\n"+"Age:"+this.age;
    }
    
    var u = new User('foo', 42);
    console.log(u.StateCredentials());

    There is no need to actually instantiate the object yourself because new does that for you.


    Our own new

    If you are asking how to basically implement new yourself, then it would be something like this:

    function User(name, age) {
      this.name = name;
      this.age = age;
    }
    
    User.prototype.StateCredentials = function() {
      return "Name:" + this.name + "\r\n" + "Age:" + this.age;
    }
    
    function newNew(constructor, ...args) {
      var instance = Object.create(constructor.prototype);
      var result = constructor.apply(instance, args);
      if (result && typeof result === 'object') {
         return result;
      }
      return instance;
    }
    
    var u = newNew(User, 'foo', 42);
    console.log(u.StateCredentials());

    Note: I'm using rest parameters (...args) for implicitly here, one could as well use arguments and slice it correctly.

    • Object.create(...) does the "magical" part of creating a new object with a specific value as it's protoype.
    • constructor.apply(...) simply calls the constructor with the new object set as its this value.
    • Then we either return the return value of the constructor if it is an object, or the object we just created.

    No new

    If you are asking how the equivalent would look like without new, constructor functions and this, then it would be something like this:

    var UserPrototype = {
      StateCredentials: function() {
          return "Name:" + this.name + "\r\n" + "Age:" + this.age;
      },
    };
    
    function makeUser(name, age) {
      var instance = Object.create(UserPrototype);
      instance.name = name;
      instance.age = age;
      return instance;
    }
    
    var u = makeUser('foo', 42);
    console.log(u.StateCredentials());

    We still need Object.create to create a new object with a specific value as its prototype.


    No prototypes

    If you don't actually want to use prototypes, you can merge the objects using var instance = Object.assign({}, UserProtoype); instead or define and assign methods individually

    function StateCredentials() {
      return "Name:" + this.name + "\r\n" + "Age:" + this.age;
    }
    
    function makeUser(name, age) {
      return {
        name: name,
        age: age,
        StateCredentials: StateCredentials,
      };
    }
    
    var u = makeUser('foo', 42);
    console.log(u.StateCredentials());

    And sure, StateCredentials could be defined inside makeUser. This is an optimization step so that we creating a new copy of that function every time makeUser is called.

  • answered 2018-11-08 07:32 Yoannes Geissler

    Or you could use class for newer browsers

    class User {
      constructor(name, age) {
        this.name = name;
        this.age = age;
      }
    
      StateCredentials() {
        return "Name:"+this.name+"\r\n"+"Age:"+this.age;
      }
    }
    
    let u = new User('name', 31);
    
    console.log(u.StateCredentials());
    

  • answered 2018-11-08 07:34 Andrew Ridgway

    You're making this a lot more complicated than it has to be:

    function user(age,name){
      this.name=name;
      this.age=age;
    }
    
    user.prototype.StateCredentials = function(){
      return "Name:"+this.name+"\r\n"+"Age:"+this.age;
    }
    
    var u = new user(12, "Little Billy");
    console.log(u.StateCredentials());
    var v = new user(11, "Little Suzy");
    console.log(v.StateCredentials());
    

    Prototype is attached with the new keyword. apply isn't used in this scenario, though you would occasionally see it in a constructor function for certain types of inheritance.