[javascript] How to "properly" create a custom object in JavaScript?

I wonder about what the best way is to create an JavaScript object that has properties and methods.

I have seen examples where the person used var self = this and then uses self. in all functions to make sure the scope is always correct.

Then I have seen examples of using .prototype to add properties, while others do it inline.

Can someone give me a proper example of a JavaScript object with some properties and methods?

This question is related to javascript

The answer is


In addition to the accepted answer from 2009. If you can can target modern browsers, one can make use of the Object.defineProperty.

The Object.defineProperty() method defines a new property directly on an object, or modifies an existing property on an object, and returns the object. Source: Mozilla

var Foo = (function () {
    function Foo() {
        this._bar = false;
    }
    Object.defineProperty(Foo.prototype, "bar", {
        get: function () {
            return this._bar;
        },
        set: function (theBar) {
            this._bar = theBar;
        },
        enumerable: true,
        configurable: true
    });
    Foo.prototype.toTest = function () {
        alert("my value is " + this.bar);
    };
    return Foo;
}());

// test instance
var test = new Foo();
test.bar = true;
test.toTest();

To see a desktop and mobile compatibility list, see Mozilla's Browser Compatibility list. Yes, IE9+ supports it as well as Safari mobile.


You can also try this

    function Person(obj) {
    'use strict';
    if (typeof obj === "undefined") {
        this.name = "Bob";
        this.age = 32;
        this.company = "Facebook";
    } else {
        this.name = obj.name;
        this.age = obj.age;
        this.company = obj.company;
    }

}

Person.prototype.print = function () {
    'use strict';
    console.log("Name: " + this.name + " Age : " + this.age + " Company : " + this.company);
};

var p1 = new Person({name: "Alex", age: 23, company: "Google"});
p1.print();

Douglas Crockford discusses that topic extensively in The Good Parts. He recommends to avoid the new operator to create new objects. Instead he proposes to create customized constructors. For instance:

var mammal = function (spec) {     
   var that = {}; 
   that.get_name = function (  ) { 
      return spec.name; 
   }; 
   that.says = function (  ) { 
      return spec.saying || ''; 
   }; 
   return that; 
}; 

var myMammal = mammal({name: 'Herb'});

In Javascript a function is an object, and can be used to construct objects out of together with the new operator. By convention, functions intended to be used as constructors start with a capital letter. You often see things like:

function Person() {
   this.name = "John";
   return this;
}

var person = new Person();
alert("name: " + person.name);**

In case you forget to use the new operator while instantiating a new object, what you get is an ordinary function call, and this is bound to the global object instead to the new object.


Closure is versatile. bobince has well summarized the prototype vs. closure approaches when creating objects. However you can mimic some aspects of OOP using closure in a functional programming way. Remember functions are objects in JavaScript; so use function as object in a different way.

Here is an example of closure:

function outer(outerArg) {
    return inner(innerArg) {
        return innerArg + outerArg; //the scope chain is composed of innerArg and outerArg from the outer context 
    }
}

A while ago I came across the Mozilla's article on Closure. Here is what jump at my eyes: "A closure lets you associate some data (the environment) with a function that operates on that data. This has obvious parallels to object oriented programming, where objects allow us to associate some data (the object's properties) with one or more methods". It was the very first time I read a parallelism between closure and classic OOP with no reference to prototype.

How?

Suppose you want to calculate the VAT of some items. The VAT is likely to stay stable during the lifetime of an application. One way to do it in OOP (pseudo code):

public class Calculator {
    public property VAT { get; private set; }
    public Calculator(int vat) {
        this.VAT = vat;
    }
    public int Calculate(int price) {
        return price * this.VAT;
    }
}

Basically you pass a VAT value into your constructor and your calculate method can operate upon it via closure. Now instead of using a class/constructor, pass your VAT as an argument into a function. Because the only stuff you are interested in is the calculation itself, returns a new function, which is the calculate method:

function calculator(vat) {
    return function(item) {
        return item * vat;
    }
}
var calculate = calculator(1.10);
var jsBook = 100; //100$
calculate(jsBook); //110

In your project identify top-level values that are good candidate of what VAT is for calculation. As a rule of thumb whenever you pass the same arguments on and on, there is a way to improve it using closure. No need to create traditional objects.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures


When one uses the trick of closing on "this" during a constructor invocation, it's in order to write a function that can be used as a callback by some other object that doesn't want to invoke a method on an object. It's not related to "making the scope correct".

Here's a vanilla JavaScript object:

function MyThing(aParam) {
    var myPrivateVariable = "squizzitch";

    this.someProperty = aParam;
    this.useMeAsACallback = function() {
        console.log("Look, I have access to " + myPrivateVariable + "!");
    }
}

// Every MyThing will get this method for free:
MyThing.prototype.someMethod = function() {
    console.log(this.someProperty);
};

You might get a lot out of reading what Douglas Crockford has to say about JavaScript. John Resig is also brilliant. Good luck!


I'd like to mention that we can use either a Title or a String to declare an Object.
There are different ways on calling each type of them. See below:

_x000D_
_x000D_
var test = {_x000D_
_x000D_
  useTitle : "Here we use 'a Title' to declare an Object",_x000D_
  'useString': "Here we use 'a String' to declare an Object",_x000D_
  _x000D_
  onTitle : function() {_x000D_
    return this.useTitle;_x000D_
  },_x000D_
  _x000D_
  onString : function(type) {_x000D_
    return this[type];_x000D_
  }_x000D_
  _x000D_
}_x000D_
_x000D_
console.log(test.onTitle());_x000D_
console.log(test.onString('useString'));
_x000D_
_x000D_
_x000D_


A Pattern That Serves Me Well
var Klass = function Klass() {
    var thus = this;
    var somePublicVariable = x
      , somePublicVariable2 = x
      ;
    var somePrivateVariable = x
      , somePrivateVariable2 = x
      ;

    var privateMethod = (function p() {...}).bind(this);

    function publicMethod() {...}

    // export precepts
    this.var1 = somePublicVariable;
    this.method = publicMethod;

    return this;
};

First, you may change your preference of adding methods to the instance instead of the constructor's prototype object. I almost always declare methods inside of the constructor because I use Constructor Hijacking very often for purposes regarding Inheritance & Decorators.

Here's how I decide where which declarations are writ:

  • Never declare a method directly on the context object (this)
  • Let var declarations take precedence over function declarations
  • Let primitives take precedence over objects ({} and [])
  • Let public declarations take precedence over private declarations
  • Prefer Function.prototype.bind over thus, self, vm, etc
  • Avoid declaring a Class within another Class, unless:
    • It should be obvious that the two are inseparable
    • The Inner class implements The Command Pattern
    • The Inner class implements The Singleton Pattern
    • The Inner class implements The State Pattern
    • The Inner Class implements another Design Pattern that warrants this
  • Always return this from within the Lexical Scope of the Closure Space.

Here's why these help:

Constructor Hijacking
var Super = function Super() {
    ...
    this.inherited = true;
    ...
};
var Klass = function Klass() {
    ...
    // export precepts
    Super.apply(this);  // extends this with property `inherited`
    ...
};
Model Design
var Model = function Model(options) {
    var options = options || {};

    this.id = options.id || this.id || -1;
    this.string = options.string || this.string || "";
    // ...

    return this;
};
var model = new Model({...});
var updated = Model.call(model, { string: 'modified' });
(model === updated === true);  // > true
Design Patterns
var Singleton = new (function Singleton() {
    var INSTANCE = null;

    return function Klass() {
        ...
        // export precepts
        ...

        if (!INSTANCE) INSTANCE = this;
        return INSTANCE;
    };
})();
var a = new Singleton();
var b = new Singleton();
(a === b === true);  // > true

As you can see, I really have no need for thus since I prefer Function.prototype.bind (or .call or .apply) over thus. In our Singleton class, we don't even name it thus because INSTANCE conveys more information. For Model, we return this so that we can invoke the Constructor using .call to return the instance we passed into it. Redundantly, we assigned it to the variable updated, though it is useful in other scenarios.

Alongside, I prefer constructing object-literals using the new keyword over {brackets}:

Preferred
var klass = new (function Klass(Base) {
    ...
    // export precepts
    Base.apply(this);  //
    this.override = x;
    ...
})(Super);
Not Preferred
var klass = Super.apply({
    override: x
});

As you can see, the latter has no ability to override its Superclass's "override" property.

If I do add methods to the Class's prototype object, I prefer an object literal -- with or without using the new keyword:

Preferred
Klass.prototype = new Super();
// OR
Klass.prototype = new (function Base() {
    ...
    // export precepts
    Base.apply(this);
    ...
})(Super);
// OR
Klass.prototype = Super.apply({...});
// OR
Klass.prototype = {
    method: function m() {...}
};
Not Preferred
Klass.prototype.method = function m() {...};

You can also do it this way, using structures :

function createCounter () {
    var count = 0;

    return {
        increaseBy: function(nb) {
            count += nb;
        },
        reset: function {
            count = 0;
        }
    }
}

Then :

var counter1 = createCounter();
counter1.increaseBy(4);

To continue off of bobince's answer

In es6 you can now actually create a class

So now you can do:

class Shape {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    toString() {
        return `Shape at ${this.x}, ${this.y}`;
    }
}

So extend to a circle (as in the other answer) you can do:

class Circle extends Shape {
    constructor(x, y, r) {
        super(x, y);
        this.r = r;
    }

    toString() {
        let shapeString = super.toString();
        return `Circular ${shapeString} with radius ${this.r}`;
    }
}

Ends up a bit cleaner in es6 and a little easier to read.


Here is a good example of it in action:

_x000D_
_x000D_
class Shape {_x000D_
  constructor(x, y) {_x000D_
    this.x = x;_x000D_
    this.y = y;_x000D_
  }_x000D_
_x000D_
  toString() {_x000D_
    return `Shape at ${this.x}, ${this.y}`;_x000D_
  }_x000D_
}_x000D_
_x000D_
class Circle extends Shape {_x000D_
  constructor(x, y, r) {_x000D_
    super(x, y);_x000D_
    this.r = r;_x000D_
  }_x000D_
_x000D_
  toString() {_x000D_
    let shapeString = super.toString();_x000D_
    return `Circular ${shapeString} with radius ${this.r}`;_x000D_
  }_x000D_
}_x000D_
_x000D_
let c = new Circle(1, 2, 4);_x000D_
_x000D_
console.log('' + c, c);
_x000D_
_x000D_
_x000D_


var Person = function (lastname, age, job){
this.name = name;
this.age = age;
this.job = job;
this.changeName = function(name){
this.lastname = name;
}
}
var myWorker = new Person('Adeola', 23, 'Web Developer');
myWorker.changeName('Timmy');

console.log("New Worker" + myWorker.lastname);

I use this pattern fairly frequently - I've found that it gives me a pretty huge amount of flexibility when I need it. In use it's rather similar to Java-style classes.

var Foo = function()
{

    var privateStaticMethod = function() {};
    var privateStaticVariable = "foo";

    var constructor = function Foo(foo, bar)
    {
        var privateMethod = function() {};
        this.publicMethod = function() {};
    };

    constructor.publicStaticMethod = function() {};

    return constructor;
}();

This uses an anonymous function that is called upon creation, returning a new constructor function. Because the anonymous function is called only once, you can create private static variables in it (they're inside the closure, visible to the other members of the class). The constructor function is basically a standard Javascript object - you define private attributes inside of it, and public attributes are attached to the this variable.

Basically, this approach combines the Crockfordian approach with standard Javascript objects to create a more powerful class.

You can use it just like you would any other Javascript object:

Foo.publicStaticMethod(); //calling a static method
var test = new Foo();     //instantiation
test.publicMethod();      //calling a method

Creating an object

The easiest way to create an object in JavaScript is to use the following syntax :

_x000D_
_x000D_
var test = {_x000D_
  a : 5,_x000D_
  b : 10,_x000D_
  f : function(c) {_x000D_
    return this.a + this.b + c;_x000D_
  }_x000D_
}_x000D_
_x000D_
console.log(test);_x000D_
console.log(test.f(3));
_x000D_
_x000D_
_x000D_

This works great for storing data in a structured way.

For more complex use cases, however, it's often better to create instances of functions :

_x000D_
_x000D_
function Test(a, b) {_x000D_
  this.a = a;_x000D_
  this.b = b;_x000D_
  this.f = function(c) {_x000D_
return this.a + this.b + c;_x000D_
  };_x000D_
}_x000D_
_x000D_
var test = new Test(5, 10);_x000D_
console.log(test);_x000D_
console.log(test.f(3));
_x000D_
_x000D_
_x000D_

This allows you to create multiple objects that share the same "blueprint", similar to how you use classes in eg. Java.

This can still be done more efficiently, however, by using a prototype.

Whenever different instances of a function share the same methods or properties, you can move them to that object's prototype. That way, every instance of a function has access to that method or property, but it doesn't need to be duplicated for every instance.

In our case, it makes sense to move the method f to the prototype :

_x000D_
_x000D_
function Test(a, b) {_x000D_
  this.a = a;_x000D_
  this.b = b;_x000D_
}_x000D_
_x000D_
Test.prototype.f = function(c) {_x000D_
  return this.a + this.b + c;_x000D_
};_x000D_
_x000D_
var test = new Test(5, 10);_x000D_
console.log(test);_x000D_
console.log(test.f(3));
_x000D_
_x000D_
_x000D_

Inheritance

A simple but effective way to do inheritance in JavaScript, is to use the following two-liner :

B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;

That is similar to doing this :

B.prototype = new A();

The main difference between both is that the constructor of A is not run when using Object.create, which is more intuitive and more similar to class based inheritance.

You can always choose to optionally run the constructor of A when creating a new instance of B by adding adding it to the constructor of B :

function B(arg1, arg2) {
    A(arg1, arg2); // This is optional
}

If you want to pass all arguments of B to A, you can also use Function.prototype.apply() :

function B() {
    A.apply(this, arguments); // This is optional
}

If you want to mixin another object into the constructor chain of B, you can combine Object.create with Object.assign :

B.prototype = Object.assign(Object.create(A.prototype), mixin.prototype);
B.prototype.constructor = B;

Demo

_x000D_
_x000D_
function A(name) {_x000D_
  this.name = name;_x000D_
}_x000D_
_x000D_
A.prototype = Object.create(Object.prototype);_x000D_
A.prototype.constructor = A;_x000D_
_x000D_
function B() {_x000D_
  A.apply(this, arguments);_x000D_
  this.street = "Downing Street 10";_x000D_
}_x000D_
_x000D_
B.prototype = Object.create(A.prototype);_x000D_
B.prototype.constructor = B;_x000D_
_x000D_
function mixin() {_x000D_
_x000D_
}_x000D_
_x000D_
mixin.prototype = Object.create(Object.prototype);_x000D_
mixin.prototype.constructor = mixin;_x000D_
_x000D_
mixin.prototype.getProperties = function() {_x000D_
  return {_x000D_
    name: this.name,_x000D_
    address: this.street,_x000D_
    year: this.year_x000D_
  };_x000D_
};_x000D_
_x000D_
function C() {_x000D_
  B.apply(this, arguments);_x000D_
  this.year = "2018"_x000D_
}_x000D_
_x000D_
C.prototype = Object.assign(Object.create(B.prototype), mixin.prototype);_x000D_
C.prototype.constructor = C;_x000D_
_x000D_
var instance = new C("Frank");_x000D_
console.log(instance);_x000D_
console.log(instance.getProperties());
_x000D_
_x000D_
_x000D_


Note

Object.create can be safely used in every modern browser, including IE9+. Object.assign does not work in any version of IE nor some mobile browsers. It is recommended to polyfill Object.create and/or Object.assign if you want to use them and support browsers that do not implement them.

You can find a polyfill for Object.create here and one for Object.assign here.


Another way would be http://jsfiddle.net/nnUY4/ (i dont know if this kind of handling object creation and revealing functions follow any specific pattern)

// Build-Reveal

var person={
create:function(_name){ // 'constructor'
                        //  prevents direct instantiation 
                        //  but no inheritance
    return (function() {

        var name=_name||"defaultname";  // private variable

        // [some private functions]

        function getName(){
            return name;
        }

        function setName(_name){
            name=_name;
        }

        return {    // revealed functions
            getName:getName,    
            setName:setName
        }
    })();
   }
  }

  // … no (instantiated) person so far …

  var p=person.create(); // name will be set to 'defaultname'
  p.setName("adam");        // and overwritten
  var p2=person.create("eva"); // or provide 'constructor parameters'
  alert(p.getName()+":"+p2.getName()); // alerts "adam:eva"

Bascially there is no concept of class in JS so we use function as a class constructor which is relevant with the existing design patterns.

//Constructor Pattern
function Person(name, age, job){
 this.name = name;
 this.age = age;
 this.job = job;
 this.doSomething = function(){
    alert('I am Happy');
}
}

Till now JS has no clue that you want to create an object so here comes the new keyword.

var person1 = new Person('Arv', 30, 'Software');
person1.name //Arv

Ref : Professional JS for web developers - Nik Z