Question Comment "correctement" créer un objet personnalisé en JavaScript?


Je me demande quel est le meilleur moyen de créer un objet JavaScript qui a des propriétés et des méthodes.

J'ai vu des exemples où la personne a utilisé var self = this puis utilise self. dans toutes les fonctions pour s'assurer que la portée est toujours correcte.

Ensuite, j'ai vu des exemples d'utilisation .prototype pour ajouter des propriétés, tandis que d'autres le font en ligne.

Quelqu'un peut-il me donner un bon exemple d'un objet JavaScript avec des propriétés et des méthodes?


448
2017-10-20 15:49


origine


Réponses:


Il existe deux modèles pour implémenter des classes et des instances en JavaScript: le prototypage et la fermeture. Les deux ont des avantages et des inconvénients, et il y a beaucoup de variations prolongées. De nombreux programmeurs et bibliothèques ont des approches et des fonctions utilitaires de traitement de classes différentes sur certaines des parties les plus laides du langage.

Le résultat est qu'en compagnie mixte, vous aurez un méli-mélo de métaclasses, toutes se comportant différemment. Pire encore, la plupart des didacticiels JavaScript sont terribles et offrent une sorte de compromis intermédiaire pour couvrir toutes les bases, vous laissant très confus. (Probablement l'auteur est également confus. Le modèle d'objet de JavaScript est très différent de la plupart des langages de programmation, et dans de nombreux endroits, il est mal conçu.)

Commençons avec la manière du prototype. C'est le code natif le plus JavaScript que vous pouvez obtenir: il y a un minimum de code de surcharge et instanceof fonctionnera avec les instances de ce type d'objet.

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

Nous pouvons ajouter des méthodes à l'instance créée par new Shape en les écrivant au prototype recherche de cette fonction constructeur:

Shape.prototype.toString= function() {
    return 'Shape at '+this.x+', '+this.y;
};

Maintenant, pour la sous-classer, dans la mesure où vous pouvez appeler ce que JavaScript fait sous-classement. Nous faisons cela en remplaçant complètement cette magie étrange prototype propriété:

function Circle(x, y, r) {
    Shape.call(this, x, y); // invoke the base class's constructor function to take co-ords
    this.r= r;
}
Circle.prototype= new Shape();

avant d'y ajouter des méthodes:

Circle.prototype.toString= function() {
    return 'Circular '+Shape.prototype.toString.call(this)+' with radius '+this.r;
}

Cet exemple fonctionnera et vous verrez du code comme ça dans de nombreux tutoriels. Mais mec, ça new Shape() est moche: nous instancions la classe de base même si aucune forme réelle ne doit être créée. Il arrive à travailler dans ce cas simple parce que JavaScript est si bâclé: il permet à zéro arguments d'être passés, auquel cas x et y devenir undefined et sont affectés au prototype this.x et this.y. Si la fonction constructeur faisait quelque chose de plus compliqué, elle tomberait à plat sur son visage.

Nous devons donc trouver un moyen de créer un objet prototype contenant les méthodes et les autres membres souhaités au niveau de la classe, sans appeler la fonction constructeur de la classe de base. Pour ce faire, nous allons devoir commencer à écrire du code d'aide. C'est l'approche la plus simple que je connaisse:

function subclassOf(base) {
    _subclassOf.prototype= base.prototype;
    return new _subclassOf();
}
function _subclassOf() {};

Cela transfère les membres de la classe de base dans son prototype à une nouvelle fonction constructeur qui ne fait rien, puis utilise ce constructeur. Maintenant, nous pouvons écrire simplement:

function Circle(x, y, r) {
    Shape.call(this, x, y);
    this.r= r;
}
Circle.prototype= subclassOf(Shape);

à la place du new Shape() inexactitude. Nous avons maintenant un ensemble acceptable de primitives pour les classes construites.

Il y a quelques raffinements et extensions que nous pouvons considérer sous ce modèle. Par exemple, voici une version syntaxique-sucre:

Function.prototype.subclass= function(base) {
    var c= Function.prototype.subclass.nonconstructor;
    c.prototype= base.prototype;
    this.prototype= new c();
};
Function.prototype.subclass.nonconstructor= function() {};

...

function Circle(x, y, r) {
    Shape.call(this, x, y);
    this.r= r;
}
Circle.subclass(Shape);

Chaque version a l'inconvénient que la fonction constructeur ne peut pas être héritée, comme c'est le cas dans de nombreuses langues. Donc, même si votre sous-classe n'ajoute rien au processus de construction, elle doit rappeler d'appeler le constructeur de base avec les arguments que la base voulait. Cela peut être légèrement automatisé en utilisant apply, mais encore faut-il écrire:

function Point() {
    Shape.apply(this, arguments);
}
Point.subclass(Shape);

Une extension commune consiste donc à séparer les éléments d'initialisation dans sa propre fonction plutôt que dans le constructeur lui-même. Cette fonction peut alors hériter de la base:

function Shape() { this._init.apply(this, arguments); }
Shape.prototype._init= function(x, y) {
    this.x= x;
    this.y= y;
};

function Point() { this._init.apply(this, arguments); }
Point.subclass(Shape);
// no need to write new initialiser for Point!

Maintenant, nous venons de recevoir le même modèle de fonction constructeur pour chaque classe. Peut-être que nous pouvons déplacer cela dans sa propre fonction d'aide, donc nous ne devons pas continuer à taper, par exemple au lieu de Function.prototype.subclass, en le retournant et en laissant la fonction de la classe de base cracher sous-classes:

Function.prototype.makeSubclass= function() {
    function Class() {
        if ('_init' in this)
            this._init.apply(this, arguments);
    }
    Function.prototype.makeSubclass.nonconstructor.prototype= this.prototype;
    Class.prototype= new Function.prototype.makeSubclass.nonconstructor();
    return Class;
};
Function.prototype.makeSubclass.nonconstructor= function() {};

...

Shape= Object.makeSubclass();
Shape.prototype._init= function(x, y) {
    this.x= x;
    this.y= y;
};

Point= Shape.makeSubclass();

Circle= Shape.makeSubclass();
Circle.prototype._init= function(x, y, r) {
    Shape.prototype._init.call(this, x, y);
    this.r= r;
};

... qui commence à ressembler un peu plus à d'autres langues, quoique avec une syntaxe légèrement plus maladroite. Vous pouvez saupoudrer quelques fonctionnalités supplémentaires si vous le souhaitez. Peut-être que tu veux makeSubclass prendre et retenir un nom de classe et fournir un défaut toString En l'utilisant. Peut-être que vous voulez faire en sorte que le constructeur détecte quand il a été appelé accidentellement sans new opérateur (ce qui aboutirait souvent à un débogage très ennuyeux):

Function.prototype.makeSubclass= function() {
    function Class() {
        if (!(this instanceof Class))
            throw('Constructor called without "new"');
        ...

Peut-être que vous voulez transmettre tous les nouveaux membres et avoir makeSubclass ajoutez-les au prototype, pour vous éviter d'avoir à écrire Class.prototype... tellement beaucoup. Un grand nombre de systèmes de classe le font, par exemple:

Circle= Shape.makeSubclass({
    _init: function(x, y, z) {
        Shape.prototype._init.call(this, x, y);
        this.r= r;
    },
    ...
});

Il y a beaucoup de fonctionnalités potentielles que vous pourriez considérer comme souhaitables dans un système d'objets et personne ne s'accorde vraiment sur une formule particulière.


le manière de fermeture, puis. Cela évite les problèmes de l'héritage basé sur le prototype de JavaScript, en n'utilisant pas l'héritage du tout. Au lieu:

function Shape(x, y) {
    var that= this;

    this.x= x;
    this.y= y;

    this.toString= function() {
        return 'Shape at '+that.x+', '+that.y;
    };
}

function Circle(x, y, r) {
    var that= this;

    Shape.call(this, x, y);
    this.r= r;

    var _baseToString= this.toString;
    this.toString= function() {
        return 'Circular '+_baseToString(that)+' with radius '+that.r;
    };
};

var mycircle= new Circle();

Maintenant, chaque instance de Shape aura sa propre copie de la toString méthode (et toute autre méthode ou autre membre de la classe que nous ajoutons).

La mauvaise chose à propos de chaque instance ayant sa propre copie de chaque membre de classe est que c'est moins efficace. Si vous traitez un grand nombre d'instances sous-classées, l'héritage prototypique peut mieux vous servir. Appeler aussi une méthode de la classe de base est un peu ennuyeux comme vous pouvez le voir: nous devons nous souvenir de la méthode avant que le constructeur de la sous-classe ne l'écrase, ou il se perd.

[Aussi parce qu'il n'y a pas d'héritage ici, le instanceof l'opérateur ne fonctionnera pas; vous devrez fournir votre propre mécanisme de détection de classe si vous en avez besoin. Alors que vous pourrait manipuler les objets du prototype de la même manière qu'avec l'héritage du prototype, c'est un peu difficile et ça ne vaut pas vraiment le coup instanceof travail.]

La bonne chose à propos de chaque instance ayant sa propre méthode est que la méthode peut alors être liée à l'instance spécifique qui la possède. Ceci est utile en raison de la façon étrange de JavaScript de relier this dans les appels de méthode, ce qui a pour conséquence que si vous détachez une méthode de son propriétaire:

var ts= mycircle.toString;
alert(ts());

puis this à l'intérieur de la méthode ne sera pas l'instance Circle comme prévu (il sera en fait le global windowobjet, provoquant un débogage généralisé malheureux). En réalité, cela se produit généralement quand une méthode est prise et assignée à un setTimeout, onclick ou EventListener en général.

Avec le mode prototype, vous devez inclure une fermeture pour chaque mission de ce type:

setTimeout(function() {
    mycircle.move(1, 1);
}, 1000);

ou, à l'avenir (ou maintenant si vous piratez Function.prototype), vous pouvez aussi le faire avec function.bind():

setTimeout(mycircle.move.bind(mycircle, 1, 1), 1000);

si vos instances sont fermées, la liaison est faite gratuitement par la fermeture sur la variable d'instance (généralement appelée that ou self, bien que personnellement je déconseillerais à ce dernier comme self a déjà une autre signification différente en JavaScript). Vous n'obtenez pas les arguments 1, 1 dans l'extrait ci-dessus gratuitement cependant, de sorte que vous auriez toujours besoin d'une autre fermeture ou d'un bind() si tu as besoin de faire ça.

Il y a beaucoup de variantes sur la méthode de fermeture aussi. Vous pouvez préférer omettre this complètement, créant un nouveau that et le retourner au lieu d'utiliser le new opérateur:

function Shape(x, y) {
    var that= {};

    that.x= x;
    that.y= y;

    that.toString= function() {
        return 'Shape at '+that.x+', '+that.y;
    };

    return that;
}

function Circle(x, y, r) {
    var that= Shape(x, y);

    that.r= r;

    var _baseToString= that.toString;
    that.toString= function() {
        return 'Circular '+_baseToString(that)+' with radius '+r;
    };

    return that;
};

var mycircle= Circle(); // you can include `new` if you want but it won't do anything

Quelle est la "bonne"? Tous les deux. Lequel est "meilleur"? Cela dépend de votre situation. FWIW Je tends vers le prototypage pour l'héritage réel de JavaScript quand je fais beaucoup de choses OO, et les fermetures pour les effets de page jetables simples.

Mais les deux méthodes sont assez intuitives pour la plupart des programmeurs. Les deux ont de nombreuses variations potentiellement désordonnées. Vous rencontrerez les deux (ainsi que de nombreux schémas intermédiaires et généralement brisés) si vous utilisez le code / les bibliothèques d'autres personnes. Il n'y a pas de réponse généralement acceptée. Bienvenue dans le monde merveilleux des objets JavaScript.

[Ceci a été la partie 94 de Pourquoi JavaScript n'est pas mon langage de programmation favori.]


853
2017-10-21 00:22



J'utilise ce modèle assez fréquemment - j'ai trouvé que cela me donne une assez grande flexibilité quand j'en ai besoin. En cours d'utilisation, il est plutôt similaire aux classes de style Java.

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;
}();

Cela utilise une fonction anonyme appelée lors de la création, renvoyant une nouvelle fonction constructeur. Comme la fonction anonyme n'est appelée qu'une seule fois, vous pouvez créer des variables statiques privées (elles sont à l'intérieur de la fermeture, visibles par les autres membres de la classe). La fonction constructeur est à la base un objet Javascript standard - vous définissez des attributs privés à l’intérieur, et les attributs publics sont attachés au this variable.

Fondamentalement, cette approche combine l'approche de Crockford avec des objets Javascript standard pour créer une classe plus puissante.

Vous pouvez l'utiliser comme n'importe quel autre objet Javascript:

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

89
2017-10-20 21:57



Douglas Crockford discute largement de ce sujet dans Les bonnes parties. Il recommande d'éviter le Nouveau opérateur pour créer de nouveaux objets. Au lieu de cela, il propose de créer des constructeurs personnalisés. Par exemple:

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'});

En Javascript, une fonction est un objet et peut être utilisée pour construire des objets avec le Nouveau opérateur. Par convention, les fonctions destinées à être utilisées comme constructeurs commencent par une majuscule. On voit souvent des choses comme:

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

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

Si vous oubliez d'utiliser le Nouveauopérateur tout en instanciant un nouvel objet, ce que vous obtenez est un appel de fonction ordinaire, et ce est lié à l'objet global plutôt qu'au nouvel objet.


24
2017-10-20 16:33



Pour continuer sur la réponse de bobince

En es6, vous pouvez maintenant créer un class

Alors maintenant vous pouvez faire:

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

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

Donc, étendez-vous à un cercle (comme dans l'autre réponse), vous pouvez faire:

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}`;
    }
}

Se retrouve un peu plus propre dans es6 et un peu plus facile à lire.


En voici un bon exemple:

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

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

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}`;
  }
}

let c = new Circle(1, 2, 4);

console.log('' + c, c);


11
2018-03-17 20:20



Vous pouvez aussi le faire de cette façon, en utilisant des structures:

function createCounter () {
    var count = 0;

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

Alors :

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

6
2017-10-20 16:11



Quand on utilise l'astuce de la fermeture sur "this" lors d'un appel de constructeur, c'est pour écrire une fonction qui peut être utilisée comme callback par un autre objet qui ne veut pas appeler une méthode sur un objet. Ce n'est pas lié à "rendre la portée correcte".

Voici un objet JavaScript vanilla:

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);
};

Vous pourriez obtenir beaucoup de lecture de ce que Douglas Crockford a à dire sur JavaScript. John Resig est aussi brillant. Bonne chance!


4
2017-10-20 15:56



Une autre façon serait http://jsfiddle.net/nnUY4/ (Je ne sais pas si ce type de manipulation de création d'objets et de fonctions de révélation suit un modèle spécifique)

// 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"

4
2018-06-07 01:02



Closure est polyvalent. Bobince a bien résumé le prototype vs fermeture approches lors de la création d'objets. Cependant, vous pouvez imiter certains aspects de OOP utiliser la fermeture de manière fonctionnelle. Rappelles toi les fonctions sont des objets en JavaScript; alors utilisez la fonction comme objet d'une manière différente.

Voici un exemple de fermeture:

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

Il y a quelque temps, je suis tombé sur l'article de Mozilla sur Closure. Voici ce qui saute aux yeux: "Une fermeture permet d'associer certaines données (l'environnement) avec une fonction qui fonctionne sur ces données. Cela a des parallèles évidents avec la programmation orientée objet, où les objets nous permettent d'associer certaines données (les propriétés de l'objet) à une ou plusieurs méthodesC'était la toute première fois que je lisais un parallélisme entre la fermeture et la POO classique sans référence au prototype.

Comment?

Supposons que vous souhaitiez calculer la TVA de certains articles. La TVA est susceptible de rester stable pendant la durée de vie d'une application. Une façon de le faire en POO (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;
    }
}

Fondamentalement, vous transmettez une valeur de TVA dans votre constructeur et votre méthode de calcul peut fonctionner sur elle via fermeture. Maintenant, au lieu d'utiliser un class / constructeur, transmettez votre TVA en tant qu'argument dans une fonction. Parce que le seul truc qui vous intéresse est le calcul lui-même, renvoie une nouvelle fonction, qui est la méthode de calcul:

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

Dans votre projet, identifiez les valeurs de haut niveau qui sont les meilleures candidates pour le calcul de la TVA. En règle générale, chaque fois que vous transmettez les mêmes arguments, il existe un moyen de l'améliorer en utilisant la fermeture. Pas besoin de créer des objets traditionnels.

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


4
2018-01-25 15:21



Créer un objet

La méthode la plus simple pour créer un objet en JavaScript consiste à utiliser la syntaxe suivante:

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

console.log(test);
console.log(test.f(3));

Cela fonctionne très bien pour stocker des données de manière structurée.

Cependant, pour les cas d'utilisation plus complexes, il est souvent préférable de créer des instances de fonctions:

function Test(a, b) {
  this.a = a;
  this.b = b;
  this.f = function(c) {
return this.a + this.b + c;
  };
}

var test = new Test(5, 10);
console.log(test);
console.log(test.f(3));

Cela vous permet de créer plusieurs objets qui partagent le même "blueprint", similaire à la façon dont vous utilisez les classes, par exemple. Java.

Cela peut encore être fait plus efficacement, cependant, en utilisant un prototype.

Chaque fois que différentes instances d'une fonction partagent les mêmes méthodes ou propriétés, vous pouvez les déplacer vers le prototype de cet objet. Ainsi, chaque instance d'une fonction a accès à cette méthode ou à cette propriété, mais elle n'a pas besoin d'être dupliquée pour chaque instance.

Dans notre cas, il est logique de déplacer la méthode f au prototype:

function Test(a, b) {
  this.a = a;
  this.b = b;
}

Test.prototype.f = function(c) {
  return this.a + this.b + c;
};

var test = new Test(5, 10);
console.log(test);
console.log(test.f(3));

Héritage

Une manière simple mais efficace de faire de l'héritage en JavaScript est d'utiliser le deux-ligne suivant:

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

C'est semblable à faire ceci:

B.prototype = new A();

La principale différence entre les deux est que le constructeur de A n'est pas exécuté lors de l'utilisation Object.create, qui est plus intuitive et plus similaire à l'héritage basé sur la classe.

Vous pouvez toujours choisir de lancer le constructeur de A lors de la création d'une nouvelle instance de B en ajoutant l'ajouter au constructeur de B :

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

Si vous voulez passer tous les arguments de B à A, vous pouvez aussi utiliser Function.prototype.apply() :

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

Si vous voulez mélanger un autre objet dans la chaîne de constructeurs de B, vous pouvez combiner Object.create avec Object.assign :

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

Démo

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

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

function B() {
  A.apply(this, arguments);
  this.street = "Downing Street 10";
}

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

function mixin() {

}

mixin.prototype = Object.create(Object.prototype);
mixin.prototype.constructor = mixin;

mixin.prototype.getProperties = function() {
  return {
    name: this.name,
    address: this.street,
    year: this.year
  };
};

function C() {
  B.apply(this, arguments);
  this.year = "2018"
}

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

var instance = new C("Frank");
console.log(instance);
console.log(instance.getProperties());


Remarque

Object.create peut être utilisé en toute sécurité dans tous les navigateurs modernes, y compris IE9 +. Object.assign ne fonctionne pas dans n'importe quelle version d'IE ni dans certains navigateurs mobiles. Il est recommandé de polyfill  Object.create et / ou Object.assign si vous voulez les utiliser et supporter les navigateurs qui ne les implémentent pas.

Vous pouvez trouver un polyfill pour Object.create  ici  et un pour Object.assign  ici.


3
2018-02-14 11:36



En plus de la réponse acceptée de 2009. Si vous pouvez cibler les navigateurs modernes, vous pouvez utiliser le Object.defineProperty.

La méthode Object.defineProperty () définit une nouvelle propriété directement sur   un objet, ou modifie une propriété existante sur un objet, et renvoie   L'object.   La 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();

Pour voir une liste de compatibilité de bureau et de mobile, voir La liste de compatibilité du navigateur de Mozilla. Oui, IE9 + le supporte aussi bien que Safari Mobile.


0
2017-10-20 04:10



Vous pouvez aussi essayer ceci

    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();

0
2017-10-18 18:26