Как "правильно" создать пользовательский объект в JavaScript?

интересно, как лучше всего создать объект JavaScript, который имеет свойства и методы.

Я видел примеры, где человек используется var self = this и затем использует self. во всех функциях, чтобы убедиться, что область всегда верна.

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

может ли кто-нибудь дать мне правильный пример объекта JavaScript с некоторыми свойствами и методами?

15 ответов


существует две модели для реализации классов и экземпляров в JavaScript: способ прототипирования и способ закрытия. Оба имеют преимущества и недостатки, и есть много расширенных вариаций. Многие программисты и библиотеки имеют разные подходы и функции утилиты обработки классов для обработки некоторых уродливых частей языка.

в результате в смешанной компании у вас будет мешанина метаклассов, все ведут себя немного по-разному. Что хуже того, большинство учебников JavaScript ужасны и служат своего рода компромиссом между ними, чтобы охватить все базы, оставив вас в замешательстве. (Возможно, автор тоже запутался. Объектная модель JavaScript сильно отличается от большинства языков программирования и во многих местах плохо спроектирована.)

с прототип способ. Это самый JavaScript-родной язык, который вы можете получить: существует минимум кода накладных расходов, и instanceof будет работать с примеры такого рода объектов.
function Shape(x, y) {
    this.x= x;
    this.y= y;
}

мы можем добавить методы к экземпляру, созданные new Shape написав их в prototype поиск этой функции конструктора:

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

теперь подкласс, насколько вы можете назвать, что JavaScript делает подклассы. Мы делаем это, полностью заменив эту странную магию prototype свойства:

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

перед добавлением методов к нему:

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

этот пример будет работать и вы увидите код нравится во многих учебниках. Но человек, это new Shape() уродливо: мы создаем экземпляр базового класса, даже если фактическая форма не должна быть создана. Это работает в этом простом случае, потому что JavaScript настолько небрежен: он позволяет передавать нулевые Аргументы, и в этом случае x и y стать undefined и присваиваются прототипу this.x и this.y. Если бы функция конструктора делала что-то более сложное, она бы упала на свою поверхность.

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

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

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

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

вместо new Shape() неправоте. Теперь у нас есть приемлемый набор примитивов для построенных классов.

есть несколько уточнений и расширений, которые мы можем рассматривать в рамках этой модели. Например, вот синтаксически-сахарная версия:

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

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

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

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

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!

теперь у нас есть только одна и та же функция конструктора для каждого класса. Может, мы сможем это убрать? в свою собственную вспомогательную функцию, поэтому нам не нужно вводить ее, например, вместо Function.prototype.subclass, поворачивая его и позволяя функции базового класса выплевывать подклассы:

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

...который начинает выглядеть немного больше похожим на другие языки, хотя и с немного неуклюжим синтаксисом. Вы можете посыпать несколько дополнительных функций, если хотите. Может быть, вы хотите makeSubclass чтобы взять и запомнить имя класса и предоставить по умолчанию toString использовать его. Возможно, вы хотите сделать конструктор обнаружьте, когда он случайно был вызван без new оператор (который в противном случае часто приводил бы к очень раздражающей отладке):

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

может быть, вы хотите передать все новых членов и makeSubclass добавьте их в прототип, чтобы вам не пришлось писать Class.prototype... довольно многое. Многие системы классов делают это, например:

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

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


на закрытие путь, затем. Это позволяет избежать проблем наследования на основе прототипов JavaScript, не используя наследование вообще. Вместо этого:

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

теперь каждый отдельный экземпляр Shape будет своя копия!--30--> метод (и любые другие методы или другие члены класса, которые мы добавляем).

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

[также потому, что здесь нет наследования,instanceof оператор не будет работать; вам придется предоставить свой собственный механизм для обнюхивания классов, Если вам это нужно. В то время как вы мог бы fiddle прототип объектов таким же образом, как с прототипом наследования, это немного сложно и не стоит того, чтобы просто получить instanceof работает.]

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

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

затем this внутри метода не будет экземпляра круга, как ожидалось (на самом деле это будет global window объект, вызывающий широко распространенное горе отладки). На самом деле это обычно происходит, когда метод берется и присваивается setTimeout, onclick или EventListener в целом.

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

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

или в будущем (или сейчас, если вы взломать Функция.прототип) вы также можете сделать это с помощью function.bind():

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

если ваши экземпляры сделаны способом закрытия, привязка выполняется бесплатно закрытием над переменной экземпляра (обычно называемой that или self, хотя лично я бы не советовал последнее как self уже имеет другой смысл в JavaScript). Вы не получите аргументы 1, 1 в приведенном выше фрагменте бесплатно, поэтому вам все равно понадобится другое закрытие или bind() если вы нужно это сделать.

существует множество вариантов метода закрытия. Вы можете предпочесть опустить this полностью, создавая новый that и возвращая его вместо использования new оператор:

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

какой путь "правильный"? Оба. Что "лучше"? Это зависит от ситуации. FWIW я склоняюсь к прототипированию для реального наследования JavaScript, когда я делаю сильно OO вещи, и закрытия для простых одноразовых эффектов страницы.

но для большинства программистов оба эти способа противоречат интуиции. Оба имеют много потенциальных грязных вариаций. Вы встретите оба (а также многие промежуточные и обычно сломанные схемы), если вы используете код/библиотеки других людей. Общепринятого ответа нет. Добро пожаловать в удивительный мир объектов JavaScript.

[это была часть 94, почему JavaScript не является моим любимым языком программирования.]


Я использую этот шаблон довольно часто - я обнаружил, что он дает мне довольно большую гибкость, когда мне это нужно. В использовании он довольно похож на классы 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;
}();

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

в принципе, этот подход сочетает в себе подход Crockfordian со стандартными объектами JavaScript для создания более мощного класса.

вы можете использовать его так же, как и любой другой объект Javascript:

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

Дуглас Крокфорд подробно обсуждает эту тему в Хорошие Части. Он рекомендует избегать новая оператор для создания новых объектов. Вместо этого он предлагает создать индивидуальные конструкторы. Например:

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

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

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

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

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


продолжить с bobince это

в es6 теперь вы можете фактически создать class

так что теперь вы можете сделать:

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

заканчивается немного чище в es6 и немного легче читать.


вот хороший пример этого в действии:

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

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

function createCounter () {
    var count = 0;

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

затем :

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

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

вот объект 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);
};

вы можете получить много от чтения what Дуглас Крокфорд должен сказать о JavaScript. Джон В Отставку тоже бриллиант. Удачи!


другой способ был бы http://jsfiddle.net/nnUY4/ (я не знаю, следует ли этот вид обработки создания объектов и выявления функций какому-либо конкретному шаблону)

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

Closure - Это универсальный. bobince хорошо обобщил прототип и закрытие подходы при создании объектов. Однако вы можете имитировать некоторые аспекты OOP используя закрытие в функциональном стиле программирования. Помни!--8-->функции являются объектами в JavaScript; поэтому используйте функцию как объект по-другому.

вот пример закрытия:

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

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

как?

Предположим, вы хотите рассчитать НДС некоторые элементы. НДС, вероятно, останется стабильным в течение срока действия заявки. Один из способов сделать это в ООП (псевдо код):

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

в основном вы передаете значение НДС в свой конструктор, и ваш метод расчета может работать с ним через закрытие. Теперь вместо использования класса / конструктора передайте свой НДС в качестве аргумента в функцию. Потому что единственное, что вас интересует сам расчет, возвращает новую функцию, которая вычислит метод:

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

в вашем проекте определите значения верхнего уровня, которые являются хорошим кандидатом на то, что НДС для расчета. Как правило, всякий раз, когда вы передаете одни и те же аргументы, есть способ улучшить его с помощью закрытия. Нет необходимости создавать традиционные объекты.

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


создание объекта

самый простой способ создать объект в JavaScript - использовать следующий синтаксис:

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

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

это работает отлично подходит для хранения данных в структурированном виде.

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

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

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

это все еще можно сделать более эффективно, однако, используя прототип.

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

в нашем случае, имеет смысл перенести метод f к прототипу :

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

наследование

простой, но эффективный способ наследования в JavaScript-использовать следующий двухстрочный:

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

, похожее на это :

B.prototype = new A();

основное различие между ними заключается в том, что конструктор A не запускается при использовании Object.create, что более интуитивно и более похоже на наследование на основе классов.

вы можете всегда выбирайте при необходимости запустить конструктор A при создании нового экземпляра B добавив его в конструктор B :

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

если вы хотите передать все аргументы B to A, вы также можете использовать Function.prototype.apply() :

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

если вы хотите смешать другой объект в цепочку конструкторов B, вы можете комбинировать Object.create С Object.assign :

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

демо

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

Примечание

Object.create можно безопасно использовать в каждом современном браузере, включая IE9+. Object.assign не работает ни в одной версии IE, ни в некоторых мобильных браузерах. Рекомендуется polyfill Object.create и/или Object.assign если вы хотите использовать их и поддерживать браузеры, которые не реализуют их.

вы можете найти polyfill для Object.create здесь и Object.assign здесь.


в дополнение к принятому ответу от 2009. Если вы можете ориентироваться на современные браузеры, можно использовать в Mozilla Список совместимости. Да, IE9 + поддерживает его, а также Safari mobile.


вы также можете попробовать это

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

Шаблон, Который Служит Мне Хорошо

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

во-первых, вы можете изменить свои предпочтения добавление методов в экземпляр вместо конструктора prototype объект. Я почти всегда объявляю методы внутри конструктора, потому что я использую Конструктор Угон очень часто для целей, касающихся наследования и декораторов.

вот как я решаю, где какие заявления приказ:

  • никогда не объявляйте метод непосредственно на объект контекста (this)
  • пусть var объявления имеют приоритет над function декларации
  • пусть примитивы имеют приоритет над объектами ({} и [])
  • пусть public объявления имеют приоритет над private декларации
  • предпочитаю Function.prototype.bind над thus, self, vm, etc
  • избегайте объявления класса в другом классе, если только:
    • это должно быть очевидно, что эти двое неразлучны!--47-->
    • внутренний класс реализует шаблон команды
    • внутренний класс реализует паттерн Singleton
    • внутренний класс реализует шаблон состояния
    • внутренний класс реализует другой шаблон проектирования, который гарантирует, что это
  • всегда возвращает this внутри Лексической Области пространства закрытия.

вот почему эти помогите!--42--> Угон Конструктора

var Super = function Super() {
    ...
    this.inherited = true;
    ...
};
var Klass = function Klass() {
    ...
    // export precepts
    Super.apply(this);  // extends this with property `inherited`
    ...
};
Модель Дизайн
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
шаблон проектирования
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

как вы можете видеть, мне действительно не нужно thus так как я предпочитаю Function.prototype.bind (или .call или .apply) за thus. В нашем Singleton класс, мы даже не называем его thus, потому что INSTANCE передает больше информации. Для Model возвращение this чтобы мы могли вызвать конструктор с помощью .call чтобы вернуть экземпляр, который мы передали в него. Избыточно, мы присвоено переменной updated, хотя это полезно в других сценариях.

наряду с этим я предпочитаю строить объектные литералы с помощью new ключевое слово над {скобки}:

Предпочтительный
var klass = new (function Klass(Base) {
    ...
    // export precepts
    Base.apply(this);  //
    this.override = x;
    ...
})(Super);
Не Рекомендуется
var klass = Super.apply({
    override: x
});

как вы можете видеть, последний не имеет возможности переопределить свойство "override" своего суперкласса.

если я добавлю методы в класс prototype object, я предпочитаю объектный литерал - С или без использования new ключевое слово:

Предпочтительный
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() {...}
};
Не Рекомендуется
Klass.prototype.method = function m() {...};

Я хотел бы отметить, что мы можем использовать заголовок или строка для объявления объекта.
Существуют различные способы вызова каждого из них. См. ниже:

var test = {

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

console.log(test.onTitle());
console.log(test.onString('useString'));

в основном нет понятия класса в JS, поэтому мы используем функцию как конструктор класса, который имеет отношение к существующим шаблонам проектирования.

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

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

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

Ref: профессиональный JS для веб-разработчиков-Nik Z


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