I am trying to pass to my class constructor an object with predefined properties.
like this
class Test {
constructor({
a = "test a",
b = "test b"
}) {
}
}
P.S. I know how to define properties of objects. I want to know how to predefine properties.
It seems you want to pass one object to the constructor and have its properties assigned to single keys of the class. You can use destructuring for that this way:
class MyClass {
constructor({a,b} = {a:1,b:2}) {
this.a = a;
this.b = b;
}
}
Be aware that this is not safe for partially filled objects:
var instance = new MyClass({a:3});
// instance.b == undefined
Handling this could be done like so:
class MyClass {
constructor({a=1,b=2} = {}) {
this.a = a;
this.b = b;
}
}
Which results in:
var instance = new MyClass({a:3});
// instance.a == 3
// instance.b == 2
The simple solution would be to pass the constructor and object during instantiation:
class Test {
constructor(obj){
this.a = obj.a;
this.b = obj.b;
}
};
const obj = {
a: 'value',
b: 'value'
};
const newtTest = new Test(obj);
Like I said in my comment, there's an example right at the top of the documentation.
class Test {
constructor(/* put arguments here if you want to pass any */){
//Pre-define a and b for any new instance of class Test
this.a = "test a";
this.b = "test b";
}
}
Related
I have created an object by defining the 'new' keyword from the object literal. But the problem is I can't access that object without looping. so is there any way to access that object?
const animal = {
animalDetails: function(a, b) {
this.a = a
this.b = b
},
animalOutPut: function() {
console.log(this.a, this.b)
},
}
// passing output by parameter ................................................................
animal.animalDetails('ape', 'Baboon')
// Call the object animal ................................................................
animal.animalOutPut()
// Create New Object Fruits from animal object literal ................................................................
let fruits = new animal.animalDetails('Apple', 'Blackberries')
for (let v in fruits) {
console.log(fruits[v])
}
You want a class
class animal {
constructor(a, b){
this.a = a;
this.b = b;
}
animalOutput(){
console.log(this.a, this.b);
}
}
You can easily define the class let tiger = new animal("tiger", "grrr")
A class allows you to create multiple of them as well, much more useful then an object.
Hope this helped!
You don't need to loop it. You can access the a and b properties just like you can with animal.
You can't use fruits.animalOutput() because animalOutput is a property only of the animal object. This object is not a prototype of objects created using new animalDetails(), so there's no inheritance.
const animal = {
animalDetails: function(a, b) {
this.a = a
this.b = b
},
animalOutPut: function() {
console.log(this.a, this.b)
},
}
// passing output by parameter ................................................................
animal.animalDetails('ape', 'Baboon')
// Call the object animal ................................................................
animal.animalOutPut()
// Create New Object Fruits from animal object literal ................................................................
let fruits = new animal.animalDetails('Apple', 'Blackberries')
console.log(fruits.a, fruits.b);
This question already has answers here:
Is there a way to provide named parameters in a function call in JavaScript?
(12 answers)
Closed 2 years ago.
Say I have a class
class Something {
constructor(a, b) {
this.a = a;
this.b = b;
}
}
How can I instantiate an object so that I only assign a value to b without assigning a value to a ?
e.g. something along the lines of:
let someObject = new Something(b : 10);
with the expected output:
log(someObject.a) // undefined
log(someObject.b) // 10
I want to avoid let someObject = new Something(undefined, 10); if I can for code readability reasons.
I'm kinda new to js, and I'm not really sure if this is even possible, but any help or guidance would be greatly appreciated!
You can do like:
class Something{
// private properties don't even work in Firefox and the syntax is just more typing than constructors
constructor(b, a){
this.a = a;
this.b = b;
}
}
const something = new Something(10);
console.log(something);
But I would do:
function Something(b, a){
let see = 'Wow these private varibles are really easy to use in costructors! Classes are lame!';
this.a = a; this.b = b;
}
const something = new Something(10);
console.log(something);
After reading your comment:
function Something(){
this.objects = [].slice.call(arguments);
this.getObjIndex = obj=>{
return this.objects.indexOf(obj);
}
this.getObjByIndex = index=>{
return this.objects[index];
}
}
const objTest1 = {test:1}, objTest2 = {test:2}, objTest3 = {really:'cool', why:['a', 2, 'z']};
const something = new Something(objTest1, objTest3);
console.log(something.objects);
console.log(something.getObjIndex(objTest3));
console.log(something.getObjByIndex(0));
#VLAZ had so many comments (which I have no problem with, by the way) that I have to show about private variables:
function PrivateTest(){
let test = 'cool';
this.getTest = ()=>{
return test;
}
this.setTest = mixed=>{
test = mixed;
return this;
}
}
const pt = new PrivateTest;
console.log(pt.getTest());
console.log(pt.setTest('Look, VLAZ, it works!').getTest());
I have 3 different classes A, B, C.
A is, essentially, the parent of both B and C. When building both B and C object, A has to be included too.
Eventually, the class returns an object, which is currently B (inherits A), or C (inherits A), or just A.
Initialising of new object:
const A = new A("a", "b", "c").json(); or const C = new C("a", "b", "c", "cClass1", "cClass2").json();
At the moment, I use inheritance to achieve this:
export class A {
constructor (option1, option2, option3) {
this.option1 = option1;
this.option2 = option2;
this.option3 = option3;
}
json () {
return {
key1: this.option1,
key2: this.option2,
key3: this.option3,
};
}
}
export class B extends A {
constructor (option1, option2, option3, bClass1, bClass2) {
super(option1, option2, option3);
this.bClassKey1 = bClass1;
this.bClassKey2 = bClass2;
}
json () {
return {
...super.json(),
bClassKey1: this.bClass1,
bClassKey2: this.bClass2
};
}
}
export class C extends A {
constructor (option1, option2, option3, cClass1, cClass2) {
super(option1, option2, option3);
this.cClassKey1 = cClass1;
this.cClassKey2 = cClass2;
}
json () {
return {
...super.json(),
cClassKey1: this.cClass1,
cClassKey2: this.cClass2
};
}
}
I now need to change how the objects are built, because I need to achieve the following:
I need an object that contains all of the classes unique parameters, like so:
{
key1: option1,
key2: option2,
key3: option3,
bClassKey1: bClass1,
bClassKey2: bClass2,
cClassKey1: cClass1,
cClassKey2: cClass2
}
However, I cannot use multiple inheritance in JS (apart from mixin NPM, but I'd rather attempt to achieve it natively).
How can I return a object, that's built with A parameters, B parameters (without A) and C parameters (without A). However, there's still situations where B and C need to be built, that extends the parent of A.
It sounds like you want to use aggregation rather than inheritance. Then, each of the classes would have a method that added its information to an object, and you'd use any combination of those methods you wanted.
/*export*/ class A {
constructor (option1, option2, option3) {
this.option1 = option1;
this.option2 = option2;
this.option3 = option3;
}
json (target = {}) {
// Could also use Object.assign here if **all** enumerable properties are desired
target.key1 = this.option1;
target.key2 = this.option2;
target.key3 = this.option3;
return target;
}
}
/*export*/ class B {
constructor (bClass1, bClass2) {
this.bClassKey1 = bClass1;
this.bClassKey2 = bClass2;
}
json (target = {}) {
// Could also use Object.assign here if **all** enumerable properties are desired
// (Duplicating the names introduces the opportunity of error, which in fact
// there was in the question)
target.bClassKey1 = this.bClassKey1;
target.bClassKey2 = this.bClassKey2;
return target;
}
}
/*export*/ class C {
constructor (cClass1, cClass2) {
this.cClassKey1 = cClass1;
this.cClassKey2 = cClass2;
}
json (target = {}) {
// Could also use Object.assign here if **all** enumerable properties are desired
// (Duplicating the names introduces the opportunity of error, which in fact
// there was in the question)
target.cClassKey1 = this.cClassKey1;
target.cClassKey2 = this.cClassKey2;
return target;
}
}
const a = new A("option1value", "option2value", "option3value");
const b = new B("bClass1value", "bClass2value");
const c = new C("cClass1value", "cClass2value");
const o = c.json(b.json(a.json()));
/* Or, but it requires more temporary objects:
const o = {...a.json(), ...b.json(), ...c.json()};
*/
console.log(o);
Lets say I have a class defined as follows:
class MyClass {
constructor(a, b) {
this._a = a;
this._b = b;
}
get a() {
return this._a;
}
set a(val) {
this._a = val;
}
add() {
return this._a + this._b;
}
}
I want to be able to access and manipulate the getter and setter functions directly at runtime in order to wrap them in additional debugging code. With the 'add' function, I can do this:
let oldAdd = MyClass.prototype.add;
MyClass.prototype.add = function() {
console.log('add called!');
let result = oldAdd.call(this);
console.log('add result: ' + result);
return result;
}
However, I cannot find a way to modify the getter and setter functions in a similar way.
I have tried
let propDef = Reflect.getOwnPropertyDescriptor(MyClass.prototype, 'a');
propDef.get = function() {
// ...
}
But this change does not actually get applied.
Any ideas?
I am also interested to know if it's possible to access and modify the constructor function in the same way.
Yes, you can do that by reconfiguring the properties. Here's an example (see comments):
class MyClass {
constructor(a, b) {
this._a = a;
this._b = b;
}
get a() {
return this._a;
}
set a(val) {
this._a = val;
}
add() {
return this._a + this._b;
}
}
// Use it before redefining
const instance = new MyClass(1, 2);
console.log(instance.a); // 1
instance.a = 2;
console.log(instance.a); // 2
// Redefine the property
const desc = Reflect.getOwnPropertyDescriptor(MyClass.prototype, "a");
const {get: originalGet, set: originalSet} = desc;
desc.get = function() {
const value = originalGet.call(this);
console.log("Debugging 'get' here, a's value is " + value);
return value;
};
desc.set = function(newValue) {
console.log("Debugging 'set' here, a's new value is " + newValue);
originalSet.call(this, newValue);
};
Object.defineProperty(MyClass.prototype, "a", desc);
// Use it after redefining
console.log(instance.a); // 2, after seeing console statement
instance.a = 3; // Triggers another console statement
console.log(instance.a); // 3 (w/ console statement)
The reason what you did didn't work was partially that you never set the new descriptor on the object. The descriptor you get back doesn't provide direct access to the definition within the object, it's just a new object created by getOwnPropertyDescriptor. To make changes effective, you need to set the new descriptor.
You asked below about doing the same for MyClass itself. As you pointed out, in addition to replacing the function, we need to be sure that its properties show up on the replacement for it.
A simple, easy way to do that is to make the new function inherit from the old:
const originalConstructor = MyClass;
MyClass = class MyClass extends originalConstructor {
constructor(...args) {
return new originalConstructor(...args);
}
};
It's a little-known fact that when B extends A, there are two things that happen:
B.prototype's prototype is set to A.prototype (this is commonly known), and
B's prototype is set to A (less well-known)
So any statics on A are available on B through inheritance.
So:
class Base {
feature() {}
static staticFeature() {}
}
class MyClass extends Base {
subFeature() {}
static staticSubFeature() {}
}
const originalConstructor = MyClass;
MyClass = class MyClass extends originalConstructor {
constructor(...args) {
return new originalConstructor(...args);
}
};
console.log(typeof MyClass.staticFeature);
console.log(typeof MyClass.staticSubFeature);
const instance = new MyClass();
console.log(typeof instance.feature);
console.log(typeof instance.subFeature);
Or if you want a really high-fidelity copy, you'd derive from MyClass's prototype and then copy over any MyClass own properties; but it's more complicated:
const originalConstructor = MyClass;
MyClass = class MyClass extends Object.getPrototypeOf(originalConstructor) {
constructor(...args) {
return new originalConstructor(...args);
}
};
Object.getOwnPropertyNames(originalConstructor)
.concat(Object.getOwnPropertySymbols(originalConstructor))
.forEach(name => {
MyClass[name] = originalConstructor[name];
});
Example:
class Base {
feature() {}
static staticFeature() {}
}
class MyClass extends Base {
subFeature() {}
static staticSubFeature() {}
}
const originalConstructor = MyClass;
MyClass = class MyClass extends Object.getPrototypeOf(originalConstructor) {
constructor(...args) {
return new originalConstructor(...args);
}
};
Object.getOwnPropertyNames(originalConstructor)
.concat(Object.getOwnPropertySymbols(originalConstructor))
.forEach(name => {
MyClass[name] = originalConstructor[name];
});
console.log(typeof MyClass.staticFeature);
console.log(typeof MyClass.staticSubFeature);
const instance = new MyClass();
console.log(typeof instance.feature);
console.log(typeof instance.subFeature);
function myClass(a,b,c) {
this.alertMyName=function(){alert(instancename)}
{...}
}
and then
foo = myClass(a,b,c);
boo = myClass(a,b,c);
foo.alertMyName(); //it should alert 'foo'
boo.alertMyName(); //it should alert 'boo'
In practice I'll need it for class that is creating a lot of html objects to prefix their ID's to differentiate them from same object created by another instance of this class.
I Couldn't find a solution on Stack Overflow so here is a solution I found from ronaldcs on dforge.net:
http://www.dforge.net/2013/01/27/how-to-get-the-name-of-an-instance-of-a-class-in-javascript/
myObject = function () {
this.getName = function () {
// search through the global object for a name that resolves to this object
for (var name in window)
if (window[name] == this)
return name;
};
};
Try it Out:
var o = new myObject();
alert(o.getName()); // alerts "o"
You could bring it in as a parameter:
function myClass(name, a, b, c) {
this.alertMyName = function(){ alert(name) }
}
foo = new myClass('foo', a, b, c);
Or assign it afterwards:
function myClass(a, b, c) {
this.setName = function(name) {
this.name = name;
}
this.alertMyName = function(){
alert(this.name)
}
}
foo = new myClass( a,b,c);
foo.setName('foo');
Further to David's answer, variables in javascript have a value that is either a primitive or a reference to an object. Where the value is a reference, then the thing it references has no idea what the "name" of the variable is.
Consider:
var foo = new MyThing();
var bar = foo;
So now what should foo.alertMyName() return? Or even:
(new MyThing()).alertMyName();
If you want instances to have a name, then give them a property and set its value to whatever suits.