Конструкторы в объектах JavaScript

Могут ли классы/объекты JavaScript иметь конструкторы? Как они создаются?

Ответ 1

Использование прототипов:

function Box(color) // Constructor
{
    this.color = color;
}

Box.prototype.getColor = function()
{
    return this.color;
};

Скрытие "цвета" (несколько напоминает частную переменную-член):

function Box(col)
{
   var color = col;

   this.getColor = function()
   {
       return color;
   };
}

Использование:

var blueBox = new Box("blue");
alert(blueBox.getColor()); // will alert blue

var greenBox = new Box("green");
alert(greenBox.getColor()); // will alert green

Ответ 2

Здесь шаблон, который я иногда использую для ООП-подобного поведения в JavaScript. Как вы можете видеть, вы можете имитировать частные (как статические, так и экземпляры) члены, используя закрытие. Возвращение new MyClass() - это объект с только свойствами, назначенными объекту this и в объекте prototype класса.

var MyClass = (function () {
    // private static
    var nextId = 1;

    // constructor
    var cls = function () {
        // private
        var id = nextId++;
        var name = 'Unknown';

        // public (this instance only)
        this.get_id = function () { return id; };

        this.get_name = function () { return name; };
        this.set_name = function (value) {
            if (typeof value != 'string')
                throw 'Name must be a string';
            if (value.length < 2 || value.length > 20)
                throw 'Name must be 2-20 characters long.';
            name = value;
        };
    };

    // public static
    cls.get_nextId = function () {
        return nextId;
    };

    // public (shared across instances)
    cls.prototype = {
        announce: function () {
            alert('Hi there! My id is ' + this.get_id() + ' and my name is "' + this.get_name() + '"!\r\n' +
                  'The next fellow\ id will be ' + MyClass.get_nextId() + '!');
        }
    };

    return cls;
})();

Меня спрашивают о наследовании с использованием этого шаблона, поэтому здесь идет:

// It a good idea to have a utility class to wire up inheritance.
function inherit(cls, superCls) {
    // We use an intermediary empty constructor to create an
    // inheritance chain, because using the super class' constructor
    // might have side effects.
    var construct = function () {};
    construct.prototype = superCls.prototype;
    cls.prototype = new construct;
    cls.prototype.constructor = cls;
    cls.super = superCls;
}

var MyChildClass = (function () {
    // constructor
    var cls = function (surName) {
        // Call super constructor on this instance (any arguments
        // to the constructor would go after "this" in call(…)).
        this.constructor.super.call(this);

        // Shadowing instance properties is a little bit less
        // intuitive, but can be done:
        var getName = this.get_name;

        // public (this instance only)
        this.get_name = function () {
            return getName.call(this) + ' ' + surName;
        };
    };
    inherit(cls, MyClass); // <-- important!

    return cls;
})();

И пример использования всего:

var bob = new MyClass();
bob.set_name('Bob');
bob.announce(); // id is 1, name shows as "Bob"

var john = new MyChildClass('Doe');
john.set_name('John');
john.announce(); // id is 2, name shows as "John Doe"

alert(john instanceof MyClass); // true

Как вы можете видеть, классы правильно взаимодействуют друг с другом (они разделяют статический идентификатор от MyClass, метод announce использует правильный метод get_name и т.д.)

Следует отметить необходимость скрывать свойства экземпляра. Фактически вы можете сделать функцию inherit пройденной через все свойства экземпляра (используя hasOwnProperty), которые являются функциями, и автоматически добавить свойство super_<method name>. Это позволит вам вызывать this.super_get_name() вместо того, чтобы хранить его во временном значении и вызывать его с помощью call.

Для методов прототипа вам не нужно беспокоиться об этом, но если вы хотите получить доступ к методам прототипов суперкласса, вы можете просто вызвать this.constructor.super.prototype.methodName. Если вы хотите сделать это менее подробным, вы можете, конечно, добавить удобства.:)

Ответ 3

Мне кажется, что большинство из вас дает пример getters и seters не конструктора, то есть http://en.wikipedia.org/wiki/Constructor_(object-oriented_programming).

lunched-dan был ближе, но пример не работал в jsFiddle.

В этом примере создается функция частного конструктора, которая выполняется только во время создания объекта.

var color = 'black';

function Box()
{
   // private property
   var color = '';

   // private constructor 
   var __construct = function() {
       alert("Object Created.");
       color = 'green';
   }()

   // getter
   this.getColor = function() {
       return color;
   }

   // setter
   this.setColor = function(data) {
       color = data;
   }

}

var b = new Box();

alert(b.getColor()); // should be green

b.setColor('orange');

alert(b.getColor()); // should be orange

alert(color); // should be black

Если вы хотите присвоить общедоступные свойства, конструктор может быть определен как таковой:

var color = 'black';

function Box()
{
   // public property
   this.color = '';

   // private constructor 
   var __construct = function(that) {
       alert("Object Created.");
       that.color = 'green';
   }(this)

   // getter
   this.getColor = function() {
       return this.color;
   }

   // setter
   this.setColor = function(color) {
       this.color = color;
   }

}

var b = new Box();

alert(b.getColor()); // should be green

b.setColor('orange'); 

alert(b.getColor()); // should be orange

alert(color); // should be black

Ответ 4

Итак, в чем смысл "конструктора", имущество? Не могу понять, где это могут быть полезны, любые идеи?

Точкой свойства конструктора является предоставление некоторого способа притворяться, что у JavaScript есть классы. Одна из вещей, которую вы не можете сделать, - это изменить конструктор объекта после его создания. Это осложнилось.

Я написал довольно обширную статью об этом несколько лет назад: http://joost.zeekat.nl/constructors-considered-mildly-confusing.html

Ответ 5

Пример здесь: http://jsfiddle.net/FZ5nC/

Попробуйте этот шаблон:

<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Name = Name||{};
Name.Space = Name.Space||{};

//============================================================
// Constructor - MUST BE AT TOP OF FILE
//------------------------------------------------------------
Name.Space.ClassName = function Name_Space_ClassName(){}

//============================================================
// Member Functions & Variables
//------------------------------------------------------------
Name.Space.ClassName.prototype = {
  v1: null
 ,v2: null
 ,f1: function Name_Space_ClassName_f1(){}
}

//============================================================
// Static Variables
//------------------------------------------------------------
Name.Space.ClassName.staticVar = 0;

//============================================================
// Static Functions
//------------------------------------------------------------
Name.Space.ClassName.staticFunc = function Name_Space_ClassName_staticFunc(){
}
</script>

Вы должны настроить пространство имен, если вы определяете статический класс:

<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Shape = Shape||{};
Shape.Rectangle = Shape.Rectangle||{};
// In previous example, Rectangle was defined in the constructor.
</script>

Пример класса:

<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Shape = Shape||{};

//============================================================
// Constructor - MUST BE AT TOP OF FILE
//------------------------------------------------------------
Shape.Rectangle = function Shape_Rectangle(width, height, color){
    this.Width = width;
    this.Height = height;
    this.Color = color;
}

//============================================================
// Member Functions & Variables
//------------------------------------------------------------
Shape.Rectangle.prototype = {
  Width: null
 ,Height: null
 ,Color: null
 ,Draw: function Shape_Rectangle_Draw(canvasId, x, y){
    var canvas = document.getElementById(canvasId);
    var context = canvas.getContext("2d");
    context.fillStyle = this.Color;
    context.fillRect(x, y, this.Width, this.Height);
 }
}

//============================================================
// Static Variables
//------------------------------------------------------------
Shape.Rectangle.Sides = 4;

//============================================================
// Static Functions
//------------------------------------------------------------
Shape.Rectangle.CreateSmallBlue = function Shape_Rectangle_CreateSmallBlue(){
    return new Shape.Rectangle(5,8,'#0000ff');
}
Shape.Rectangle.CreateBigRed = function Shape_Rectangle_CreateBigRed(){
    return new Shape.Rectangle(50,25,'#ff0000');
}
</script>

Пример создания экземпляра:

<canvas id="painting" width="500" height="500"></canvas>
<script>
alert("A rectangle has "+Shape.Rectangle.Sides+" sides.");

var r1 = new Shape.Rectangle(16, 12, "#aa22cc");
r1.Draw("painting",0, 20);

var r2 = Shape.Rectangle.CreateSmallBlue();
r2.Draw("painting", 0, 0);

Shape.Rectangle.CreateBigRed().Draw("painting", 10, 0);
</script>

Функции уведомлений определяются как A.B = function A_B(). Это упростит отладку script. Откройте панель Chrome Inspect Element, запустите этот script и разверните backgrace отладки:

<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Fail = Fail||{};

//============================================================
// Static Functions
//------------------------------------------------------------
Fail.Test = function Fail_Test(){
    A.Func.That.Does.Not.Exist();
}

Fail.Test();
</script>

Ответ 6

Это конструктор:

function MyClass() {}

Когда вы делаете

var myObj = new MyClass();

MyClass выполняется, и новый объект возвращается этому классу.

Ответ 7

Этот образец хорошо послужил мне. С помощью этого шаблона вы создаете классы в отдельных файлах, загружаете их в свое общее приложение "по мере необходимости".

// Namespace
// (Creating new if not instantiated yet, otherwise, use existing and just add to it)
var myApp = myApp || {};

// "Package" 
// Similar to how you would establish a package in other languages
(function() {

// "Class"
var MyClass = function(params) {
    this.initialize(params);
}

    // "Private Static" vars 
    //    - Only accessible to functions in this class.
    //    - Doesn't get wiped out when we create a new instance.
    var countInstances = 0;
    var allInstances = [];

    // "Private Static" functions 
    //    - Same as above, but it a function accessible 
    //      only to other functions in this class.
    function doSomething(){
    }

    // "Public Static" vars
    //    - Everyone has access.
    //    - Doesn't get wiped out when we create a new instance.
    MyClass.counter = 0;

    // "Public Static" functions
    //    - Same as above, but anyone can call this "static method".
    //    - Kinda like a singleton class situation.
    MyClass.foobar = function(){
    }

    // Public properties and methods are built into the "prototype"
    //    - This is how each instance can become unique unto itself.
    //    - Establishing "p" as "local" (Static Private) variable 
    //      simply so we don't have to keep typing "MyClass.prototype" 
    //      for each property and function.
var p = MyClass.prototype;

    // "Public" vars
    p.id = null;
    p.firstname = null;
    p.lastname = null;

    // "Private" vars
    //    - Only used by "this" instance.
    //    - There isn't "true" privacy for each 
    //      instance so we have to fake it. 
    //    - By tradition, we indicate "privacy"  
    //      by prefixing it with an underscore. 
    //    - So technically, anyone can access, but we simply 
    //      don't tell anyone about it (e.g. in your API)
    //      so no one knows about it :)
    p._foo = null;

    p.initialize = function(params){
        this.id = MyClass.counter++;
        this.firstname = params.firstname;
        this.lastname = params.lastname;
        MyClass.counter++;
        countInstances++;
        allInstances.push(this);
    }

    p.doAlert = function(theMessage){
        alert(this.firstname + " " + this.lastname + " said: " + theMessage + ". My id:" + this.id + ".  Total People:" + countInstances + ". First Person:" + allInstances[0].firstname + " " + allInstances[0].lastname);
    }


// Assign class to app
myApp.MyClass = MyClass;

// Close the "Package"
}());

// Usage example:
var bob = new myApp.MyClass({   firstname   :   "bob",
                                lastname    :   "er"
                            });

bob.doAlert("hello there");

Ответ 8

Я нашел этот урок очень полезным. Этот подход используется большинством плагинов jQuery.

http://www.htmlgoodies.com/html5/tutorials/create-an-object-oriented-javascript-class-constructor.html#fbid=OVYAQL_TDpK

var Class = function(methods) {   
    var klass = function() {    
        this.initialize.apply(this, arguments);          
    };  

    for (var property in methods) { 
       klass.prototype[property] = methods[property];
    }

    if (!klass.prototype.initialize) klass.prototype.initialize = function(){};      

    return klass;    
};

Теперь

var Person = Class({ 
    initialize: function(name, age) {
        this.name = name;
        this.age  = age;
    },
    toString: function() {
        return "My name is "+this.name+" and I am "+this.age+" years old.";
    }
}); 

var alice = new Person('Alice', 26);
alert(alice.name); //displays "Alice"
alert(alice.age); //displays "26"
alert(alice.toString()); //displays "My name is Alice and I am 26 years old" in most browsers.
//IE 8 and below display the Object toString() instead! "[Object object]"

Ответ 9

Да, вы можете определить конструктор внутри объявления класса следующим образом:

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

Ответ 10

Я предполагаю, что опубликую, что я делаю с закрытием javascript, так как никто еще не использует закрытие.

var user = function(id) {
  // private properties & methods goes here.
  var someValue;
  function doSomething(data) {
    someValue = data;
  };

  // constructor goes here.
  if (!id) return null;

  // public properties & methods goes here.
  return {
    id: id,
    method: function(params) {
      doSomething(params);
    }
  };
};

Комментарии и предложения к этому решению приветствуются.:)

Ответ 11

Используя пример Nick, вы можете создать конструктор для объектов без, используя оператор return в качестве последнего оператора в определении объекта. Верните свою конструкторную функцию, как показано ниже, и она будет запускать код в __construct каждый раз, когда вы создаете объект:

function Box()
{
   var __construct = function() {
       alert("Object Created.");
       this.color = 'green';
   }

  this.color = '';

   this.getColor = function() {
       return this.color;
   }

   __construct();
}

var b = new Box();

Ответ 12

Они делают, если вы используете Typescript - с открытым исходным кодом от MicroSoft: -)

class BankAccount {
 balance: number;
 constructor(initially: number) {
 this.balance = initially;
 }
 deposit(credit: number) {
 this.balance += credit;
 return this.balance;
 }
}

Typescript позволяет вам "подделывать" OO-конструкции, которые скомпилированы в конструкции javascript. Если вы запускаете большой проект, это может сэкономить вам много времени, и он просто достиг версии версии 1.0.

http://www.typescriptlang.org/Content/TypeScript%20Language%20Specification.pdf

Вышеприведенный код получает "скомпилированный":

var BankAccount = (function () {
    function BankAccount(initially) {
        this.balance = initially;
    }
    BankAccount.prototype.deposit = function (credit) {
        this.balance += credit;
        return this.balance;
    };
    return BankAccount;
})();

Ответ 13

Может быть, это получилось немного проще, но ниже - это то, что я придумал сейчас в 2017 году:

class obj {
  constructor(in_shape, in_color){
    this.shape = in_shape;
    this.color = in_color;
  }

  getInfo(){
    return this.shape + ' and ' + this.color;
  }
  setShape(in_shape){
    this.shape = in_shape;
  }
  setColor(in_color){
    this.color = in_color;
  }
}

При использовании вышеприведенного класса у меня есть следующее:

var newobj = new obj('square', 'blue');

//Here, we expect to see 'square and blue'
console.log(newobj.getInfo()); 

newobj.setColor('white');
newobj.setShape('sphere');

//Since we've set new color and shape, we expect the following: 'sphere and white'
console.log(newobj.getInfo());

Как вы можете видеть, конструктор принимает два параметра, и мы устанавливаем свойства объекта. Мы также изменяем цвет и форму объекта с помощью функций setter и доказываем, что его изменение оставалось после вызова getInfo() после этих изменений.

Немного поздно, но я надеюсь, что это поможет. Я тестировал это с помощью тестера mocha, и он хорошо работает.

Ответ 14

В JavaScript тип вызова определяет поведение функции:

  • Прямой вызов func()
  • Вызов метода для объекта obj.func()
  • Конструктор вызов new func()
  • Косвенное обращение func.call() или func.apply()

Функция вызывается с помощью конструктора при вызове с помощью оператора new:

function Cat(name) {
   this.name = name;
}
Cat.prototype.getName = function() {
   return this.name;
}

var myCat = new Cat('Sweet'); // Cat function invoked as a constructor

Любой объект экземпляра или прототипа в JavaScript имеет свойство constructor, которое ссылается на функцию конструктора.

Cat.prototype.constructor === Cat // => true
myCat.constructor         === Cat // => true

Отметьте этот пост о свойстве конструктора.

Ответ 15

При использовании большого шаблона Blixt выше, я узнал, что он не очень хорошо работает с многоуровневым наследованием (MyGrandChildClass расширяет MyChildClass, расширяя MyClass) - он циклически вызывает вызов первого родительского конструктора снова и снова. Итак, вот простой способ обхода - если вам нужно многоуровневое наследование, вместо использования this.constructor.super.call(this, surName); используйте chainSuper(this).call(this, surName); с функцией цепочки, определенной следующим образом:

function chainSuper(cls) {
  if (cls.__depth == undefined) cls.__depth = 1; else cls.__depth++;
  var depth = cls.__depth;
  var sup = cls.constructor.super;
  while (depth > 1) {
    if (sup.super != undefined) sup = sup.super;
    depth--;
  }
  return sup;
}

Ответ 16

http://www.jsoops.net/ неплохо подходит для oop в Js. Если вы предоставляете частную, защищенную, общедоступную переменную и функцию, а также функцию наследования. Пример кода:

var ClassA = JsOops(function (pri, pro, pub)
{// pri = private, pro = protected, pub = public

    pri.className = "I am A ";

    this.init = function (var1)// constructor
    {
        pri.className += var1;
    }

    pub.getData = function ()
    {
        return "ClassA(Top=" + pro.getClassName() + ", This=" + pri.getClassName()
        + ", ID=" + pro.getClassId() + ")";
    }

    pri.getClassName = function () { return pri.className; }
    pro.getClassName = function () { return pri.className; }
    pro.getClassId = function () { return 1; }
});

var newA = new ClassA("Class");

//***Access public function
console.log(typeof (newA.getData));
// function
console.log(newA.getData());
// ClassA(Top=I am A Class, This=I am A Class, ID=1)

//***You can not access constructor, private and protected function
console.log(typeof (newA.init));            // undefined
console.log(typeof (newA.className));       // undefined
console.log(typeof (newA.pro));             // undefined
console.log(typeof (newA.getClassName));    // undefined

Ответ 17

просто предложить некоторые разновидности. ds.oop - отличный способ объявить классы с конструкторами в javascript. Он поддерживает все возможные типы наследования (включая 1 тип, который даже С# не поддерживает), а также интерфейсы, которые хороши.

var Color = ds.make.class({
    type: 'Color',
    constructor: function (r,g,b) { 
        this.r = r;                     /* now r,g, and b are available to   */
        this.g = g;                     /* other methods in the Color class  */
        this.b = b;                     
    }
});
var red = new Color(255,0,0);   // using the new keyword to instantiate the class

Ответ 18

Здесь мы должны заметить одну точку в java script, но это класс без урока, но мы можем добиться этого, используя функции в java script. Наиболее распространенный способ достижения этого нам нужно создать функцию в java script и использовать новое ключевое слово для создания объекта и использовать this ключевое слово, чтобы определить свойство и методы. Ниже приведен пример.

// Function constructor

   var calculator=function(num1 ,num2){
   this.name="This is function constructor";
   this.mulFunc=function(){
      return num1*num2
   };

};

var objCal=new calculator(10,10);// This is a constructor in java script
alert(objCal.mulFunc());// method call
alert(objCal.name);// property call

//Constructors With Prototypes

var calculator=function(){
   this.name="Constructors With Prototypes";
};

calculator.prototype.mulFunc=function(num1 ,num2){
 return num1*num2;
};
var objCal=new calculator();// This is a constructor in java script
alert(objCal.mulFunc(10,10));// method call
alert(objCal.name); // property call

Ответ 19

В большинстве случаев вам нужно как-то объявить требуемое свойство, прежде чем вы сможете вызвать метод, который передает эту информацию. Если вам не нужно сначала устанавливать свойство, вы можете просто вызвать метод внутри объекта, например. Вероятно, это не самый красивый способ сделать это, но это все еще работает.

var objectA = {
    color: ''; 
    callColor : function(){
        console.log(this.color);
    }
    this.callColor(); 
}
var newObject = new objectA();