Как создать класс в JavaScript?

В JavaScript существует множество способов сделать одно и то же. Я, однако, взял некоторые способы, и некоторые способы, которых я откровенно не понимаю. Может ли кто-нибудь помочь мне прояснить некоторые вещи? (Сначала я изучил ООП в PHP.)

Таким образом, класс можно сделать следующим образом:

var object = new class(constructparams) {
    var private_members; // Can be accessed from within the code inside this definition only.
    this.public_members; // Can be accessed from everywhere.

    var private_functions = function() {}
    this.public_functions = function() {}
}

object.prototype.semi_public_members = function() {
    // Will be public, but can only access public members and methods.
    // E. g. private_members; is not available here.
}

До сих пор все это правильно?

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

И, наконец, у вас есть объектная буквальная запись, которую я не понимаю.

var object = { // Something strange in here }

Что там происходит? Это JSON? Как он используется, как я могу его использовать. Каковы преимущества использования этого метода вместо использования метода, который я описал? Почему вы прототип вместо того, чтобы сделать класс правильно в первый раз?

Ответ 1

Объяснение поведения разных объектов в построенном объекте на примере:

// Defined as a variable from an anonymous function
// so that there is scope closure over variables
// shared across all instances and the prototype.
// If this isn't important, you don't need to close
// scope around it, so define directly
var ConstructedObject = (function constructorCreator () {
    // Define any variables/methods to be shared across
    // all instances but not polluting the namespace
    var sharedVariable = 'foo';

    // Next the actual constructor
    function ConstructedObject () {
        // Variables here are normally used to help
        // each instance and will be kept in memory as
        // long as the instance exists
        var instanceVariable = 'bar';
        // instance-specific properties get defined
        // using the "this" keyword, these are the
        // properties expected to be changed across
        // each different instance
        this.instanceProperty = true;
        this.instanceMethod = function () { return instanceVariable; };
        this.changeInstanceVar = function () { instanceVariable = 'foo'; };
            // you do have access to the shared
            // variables here if you need them.
    }
    // After the constructor, you set up the
    // prototype, if any. This is an object of shared
    // properties and methods to be inherited by every
    // instance made by the constructor, and it also
    // inherits the prototype prototype, too.
    // Lets use a literal object for simplicity.
    ConstructedObject.prototype = {
        // Accessing the instance to which a method
        // applies is done using the "this" keyword,
        // similar to in the constructor
        sharedMethod : function () { return [sharedVariable, this.instanceMethod(),this.instanceProperty]; },
        changeSharedVar : function () { sharedVariable = 'bar'; }
        // properties may also be defined
    };
    // Finally, the constructor is returned so it
    // can be kept alive outside of the anonymous
    // function used to create it
    return ConstructedObject;
// and the anonymous function is called to execute
// what we've done so far
})();

После выполнения вышеуказанного кода у вас есть конструктор, который создает объекты как с конкретными экземплярами, так и с общими переменными. Теперь давайте посмотрим, как они себя ведут, создавая два экземпляра и сравнивая их до и после некоторых изменений.

// First create the two instances
var myObjA = new ConstructedObject(),
    myObjB = new ConstructedObject();
// Now compare them, the sharedMethod method we
// used in the prototype offers an easy way to
// do this
console.log( myObjA.sharedMethod(), myObjB.sharedMethod() );
// ["foo", "bar", true] ["foo", "bar", true]
// Next lets change the different variables in
// myObjB so we can see what happens, again the
// change* methods defined before let us do this
// easily
myObjB.changeInstanceVar();
myObjB.changeSharedVar();
// For completeness, lets also change the property
// on myObjB.
myObjB.instanceProperty = false;
// Now when we compare them again, we see that our
// changes to the myObjB instance have only changed
// the shared variables of myObjA
console.log( myObjA.sharedMethod(), myObjB.sharedMethod() );
// ["bar", "bar", true] ["bar", "foo", false]

Ниже приведены два записанных оператора для более удобного просмотра

//     myObjA               myObjB
["foo", "bar", true] ["foo", "bar", true]
["bar", "bar", true] ["bar", "foo", false]

Ответ 2

Я думаю, что есть некоторые концепции, которые, кажется, отсутствуют, но я постараюсь ответить как можно больше.

Таким образом, класс можно сделать следующим образом... До сих пор это правильно?

Он близок, но не совсем корректен. Вам не нужно new для создания функции-конструктора, вам это нужно только при создании нового экземпляра класса.

function Klass() { ... } // capitalized name as convention for constructors
var myKlass = new Klass(); //<-- Need "new" here

Публичные методы могут быть прикреплены к экземпляру или прототипу. Когда вы прикрепляете его к прототипу, метод будет использоваться для всех экземпляров, сохраняя некоторую память.

Klass.prototype = {
  publicSharedMethod: function() {
    var self = this;
  }
}

Затем кому-то нравится самопроизвольная анонимная функция... Что такое точка этого...

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

var Singleton = (function() {
  var private = 'foo';
  var public = 'baz';
  var publicMethod = function() { ... }
  // Expose public methods and properties
  return {
    public: public
    publicMethod: publicMethod
  }
}());

И, наконец, у вас есть объектная буквальная запись, которую я не понять.

Это просто обычный объект в JavaScript, аналогичный тому, что PHP называет "ассоциативным массивом". Синтаксис буквенных объектов является базой для JSON, но JSON имеет больше ограничений с точки зрения форматирования; JavaScript более прост, поэтому вы можете иметь некотируемые свойства и методы, например.

Почему бы вам прототип вместо правильного создания класса первый раз?

Здесь следует понимать, что JavaScript не является традиционным объектно-ориентированным языком, поэтому нет классов, и вы не должны думать о классах. Но прототипы очень мощные, я бы сказал, даже более мощный, чем классы. Есть много примеров онлайн о том, как копировать классы с прототипами, но не наоборот.

Ответ 3

Нет, это неверно. Функция-конструктор должна быть отделена от создания объекта:

function myClass(constructparam1) {
  this.public_member = constructparam1; // Can be accessed from everywhere.
}

Методы должны быть в прототипе конструктора, а не в экземпляре:

myClass.prototype.semi_public_members = function() {
  // Will be public
}

Вызов конструктора с ключевым словом new для создания экземпляра:

var obj = new myClass(1337);

Локальные переменные внутри функции конструктора могут быть доступны только внутри этой функции. Если вы не используете локальные переменные в своем классе, вам нужна функция вокруг него, чтобы создать закрытие, чтобы методы в прототипе могли получить доступ к переменным:

var myClass = (function(){

  var local_variable;

  function constructor(constructparam1) {
    this.public_member = constructparam1; // Can be accessed from everywhere.
  }

  constructor.prototype.semi_public_members = function() {
    // Will be public
    alert(local_variable); // can access private variables
  }

  return constructor;
})();

Объектные литералы - это простой, но ограниченный способ создания объектов за один раз. У них нет прототипа, поэтому, если вы хотите, чтобы у них были методы, вы должны назначить их свойствам:

var obj = {

  public_member: 1337,

  semi_public_members: function(){
    alert(this.public_member);
  }

};

Ответ 4

var object = new function () {
    //
}

var myObject = new object();