As classes / objetos JavaScript podem ter construtores? Como eles são criados?
As classes / objetos JavaScript podem ter construtores? Como eles são criados?
Respostas:
Usando protótipos:
function Box(color) // Constructor
{
this.color = color;
}
Box.prototype.getColor = function()
{
return this.color;
};
Ocultação de "cor" (lembra um pouco uma variável de membro particular):
function Box(col)
{
var color = col;
this.getColor = function()
{
return color;
};
}
Uso:
var blueBox = new Box("blue");
alert(blueBox.getColor()); // will alert blue
var greenBox = new Box("green");
alert(greenBox.getColor()); // will alert green
color. Eu sugiro que você usa é em grande parte uma questão de preferência pessoal (protecção contra simplicidade)
varfaz uma variável privada. thisfaz uma variável pública
Foo, enquanto no último caso ele saberá que está Foosendo chamado. Muito útil para depuração.
Aqui está um modelo que às vezes uso para comportamentos semelhantes a OOP em JavaScript. Como você pode ver, você pode simular membros privados (estáticos e de instância) usando fechamentos. O new MyClass()que retornará é um objeto com apenas as propriedades atribuídas ao thisobjeto e no prototypeobjeto da "classe".
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\'s id will be ' + MyClass.get_nextId() + '!');
}
};
return cls;
})();
Fui questionado sobre herança usando esse padrão, então aqui vai:
// It's 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;
})();
E um exemplo para usar tudo:
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
Como você pode ver, as classes interagem corretamente umas com as outras (elas compartilham o ID estático MyClass, o announcemétodo usa o get_namemétodo correto etc.)
Uma coisa a observar é a necessidade de sombrear as propriedades da instância. Na verdade, você pode fazer a inheritfunção passar por todas as propriedades da instância (usando hasOwnProperty) que são funções e adicionar automaticamente uma super_<method name>propriedade. Isso permitiria que você chamasse em this.super_get_name()vez de armazená-lo em um valor temporário e chamá-lo vinculado usando call.
Para métodos no protótipo, você não precisa se preocupar com o exposto acima. Se você quiser acessar os métodos de protótipo da superclasse, basta ligar this.constructor.super.prototype.methodName. Se você quiser torná-lo menos detalhado, é claro que pode adicionar propriedades de conveniência. :)
cls.prototypeparte: "compartilhado entre instâncias" é apenas para ler o valor (chamando announce). Se você definir myClassInstance.announceoutro valor, ele criará uma nova propriedade em myClassInstance, portanto, somente se aplicará a esse objeto, não a outras instâncias da classe. Atribuir a MyClass.prototype.announceafetará todas as instâncias.
MyClass.get_nextId()
Parece-me que muitos de vocês estão dando exemplos de getters e setters, não um construtor, ou seja, http://en.wikipedia.org/wiki/Constructor_(object-oriented_programming) .
O lunch-dan estava mais próximo, mas o exemplo não funcionou no jsFiddle.
Este exemplo cria uma função de construtor particular que é executada apenas durante a criação do objeto.
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
Se você deseja atribuir propriedades públicas, o construtor pode ser definido como tal:
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
Box()função :). Mas este exemplo, bem como exemplos nas outras respostas, podem ser facilmente estendidos para aceitar parâmetros.
Boxfunção e você estará pronto (ainda é "privado"). "Privado" em Javascript significa apenas acessível via escopo lexical; não há necessidade de atribuir aos membros. Além disso: esse código está errado. Ele cria uma __constructvariável global , o que é bastante ruim. vardeve ser usado para restringir o escopo de __construct.
Então, qual é o objetivo da propriedade "construtora"? Não consegue descobrir onde poderia ser útil, alguma idéia?
O objetivo da propriedade construtor é fornecer uma maneira de fingir que o JavaScript tem classes. Uma das coisas que você não pode fazer com utilidade é alterar o construtor de um objeto depois que ele é criado. É complicado.
Eu escrevi uma peça bastante abrangente sobre isso há alguns anos: http://joost.zeekat.nl/constructors-considered-mildly-confusing.html
Exemplo aqui: http://jsfiddle.net/FZ5nC/
Experimente este modelo:
<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>
Você deve ajustar seu espaço para nome se estiver definindo uma classe estática:
<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Shape = Shape||{};
Shape.Rectangle = Shape.Rectangle||{};
// In previous example, Rectangle was defined in the constructor.
</script>
Classe de exemplo:
<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>
Instanciação de exemplo:
<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>
As funções de aviso são definidas como AB = função A_B (). Isso é para facilitar a depuração do seu script. Abra o painel Inspect Element do Chrome, execute este script e expanda o backtrace de depuração:
<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Fail = Fail||{};
//============================================================
// Static Functions
//------------------------------------------------------------
Fail.Test = function Fail_Test(){
A.Func.That.Does.Not.Exist();
}
Fail.Test();
</script>
Este é um construtor:
function MyClass() {}
Quando você faz
var myObj = new MyClass();
MyClass é executado e um novo objeto é retornado dessa classe.
alert(valuePassedInAsArgument);e isso será executado uma vez a cada instanciação, portanto, toda a classe é o próprio construtor.
new object is returned of that class- não é mais como um novo objeto é retornado dessa função?
Achei este tutorial muito útil. Essa abordagem é usada pela maioria dos plug-ins do jQuery.
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;
};
Agora ,
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's toString() instead! "[Object object]"
klass
Esse padrão me serviu bem. Com esse padrão, você cria classes em arquivos separados, carrega-as no seu aplicativo geral "conforme necessário".
// 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's 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");
varno construtor (ou argumento da função ou em uma função semelhante ao construtor).
Sim, você pode definir um construtor dentro de uma declaração de classe como esta:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
Acho que vou postar o que faço com o fechamento de javascript, pois ninguém está usando o fechamento ainda.
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);
}
};
};
Comentários e sugestões para esta solução são bem-vindos. :)
Usando a amostra de Nick acima, você pode criar um construtor para objetos sem parâmetros usando uma instrução de retorno como a última instrução na sua definição de objeto. Retorne sua função de construtor conforme abaixo e ele executará o código em __construct toda vez que você criar o objeto:
function Box()
{
var __construct = function() {
alert("Object Created.");
this.color = 'green';
}
this.color = '';
this.getColor = function() {
return this.color;
}
__construct();
}
var b = new Box();
this.getColor();na linha acima, alert("Object Created.");nada será alertado. Ocorrerá um erro como "getColor não está definido". Se você deseja que a construção possa chamar outros métodos no objeto, ela precisa ser definida após todos os outros métodos. Então, ao invés de chamar __construct();a última linha, apenas defina a construção lá embaixo e coloque-a ()depois para forçá-la a executar automaticamente.
()ao final da definição de construção ainda resultou no erro. Eu tive que chamar __construct();em sua própria linha, como no código original, para evitar o erro.
Talvez tenha ficado um pouco mais simples, mas abaixo está o que eu criei agora em 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;
}
}
Ao usar a classe acima, tenho o seguinte:
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());
Como você pode ver, o construtor utiliza dois parâmetros e definimos as propriedades do objeto. Também alteramos a cor e a forma do objeto usando as setterfunções e provamos que sua alteração permaneceu após a chamada getInfo()após essas alterações.
Um pouco tarde, mas espero que isso ajude. Eu testei isso com um mochateste de unidade e está funcionando bem.
Eles fazem se você usar o Typescript - código aberto da MicroSoft :-)
class BankAccount {
balance: number;
constructor(initially: number) {
this.balance = initially;
}
deposit(credit: number) {
this.balance += credit;
return this.balance;
}
}
O TypeScript permite que você construa construções OO falsas que são compiladas em construções javascript. Se você estiver iniciando um projeto grande, poderá economizar muito tempo e atingir a versão 1.0 do marco.
http://www.typescriptlang.org/Content/TypeScript%20Language%20Specification.pdf
O código acima é 'compilado' para:
var BankAccount = (function () {
function BankAccount(initially) {
this.balance = initially;
}
BankAccount.prototype.deposit = function (credit) {
this.balance += credit;
return this.balance;
};
return BankAccount;
})();
No JavaScript, o tipo de chamada define o comportamento da função:
func()obj.func()new func()func.call()oufunc.apply()A função é chamada como um construtor ao chamar usando o newoperador:
function Cat(name) {
this.name = name;
}
Cat.prototype.getName = function() {
return this.name;
}
var myCat = new Cat('Sweet'); // Cat function invoked as a constructor
Qualquer objeto de instância ou protótipo em JavaScript tem uma propriedade constructor, que se refere à função do construtor.
Cat.prototype.constructor === Cat // => true
myCat.constructor === Cat // => true
Verifique esta postagem sobre a propriedade do construtor.
Ao usar o ótimo modelo de Blixt acima, descobri que ele não funciona bem com herança de vários níveis (MyGrandChildClass estendendo MyChildClass estendendo MyClass) - ele liga para chamar o construtor do primeiro pai repetidamente. Então, aqui está uma solução simples - se você precisar de herança em vários níveis, em vez de usar o this.constructor.super.call(this, surName);uso chainSuper(this).call(this, surName);com a função de cadeia definida assim:
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;
}
http://www.jsoops.net/ é muito bom para oop em Js. Se fornecer variável e função pública, protegida e pública, e também recurso de Herança. Código de exemplo:
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
apenas para oferecer alguma variedade. O ds.oop é uma ótima maneira de declarar classes com construtores em javascript. Ele suporta todos os tipos possíveis de herança (incluindo um tipo que até o c # não suporta), bem como interfaces, o que é bom.
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
Aqui, precisamos observar um ponto no script java, é uma linguagem sem classe, no entanto, podemos alcançá-lo usando funções no script java. A maneira mais comum de conseguir isso é criar uma função no script java e usar a nova palavra - chave para criar um objeto e usar essa palavra - chave para definir propriedades e métodos. Abaixo está o exemplo.
// 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
Na maioria dos casos, é necessário declarar de alguma forma a propriedade necessária antes de chamar um método que transmita essas informações. Se você não precisar definir inicialmente uma propriedade, basta chamar um método dentro do objeto dessa forma. Provavelmente não é a maneira mais bonita de fazer isso, mas isso ainda funciona.
var objectA = {
color: '';
callColor : function(){
console.log(this.color);
}
this.callColor();
}
var newObject = new objectA();