Use properties of user supplied object, if it exists, otherwise use defaults - javascript

So let's say I want to pass in an object containing settings to my class in JavaScript, but also provide default options, how would I do that easily? For example:
myClass = function(options){
var defaults = {
foo: 'foo',
bar: 'bar'
};
};
customOptions = {
bar: 'foobar'
};
myInstance = new myClass(customOptions);
So in this case, I would like for myInstance() to use foo='foo' since it was not specified by the user, and bar='foobar' as that was set by the user.
Now, I'll be dealing with a bigger and more complex JSON object, obviously, and it seems inefficient and hard to maintain to check every property every time, so is there some way to combine these objects easily, overwriting as needed, with the user supplied properties always taking precedence?

You could do something like this:
var MyClass = function (options) {
var defaults = {foo: 1, bar: 2};
for (var option in defaults) {
this[option] = options[option] || defaults[option];
}
}
var customOptions = { bar: 5};
var c = new MyClass(customOptions);
Basically loop through the custom options passed in and add any missing options with their defaults. In this case c.foo = 1 and c.bar = 5. Fiddle available at http://jsfiddle.net/2Ve3M/.

You can check if the custom options object contains the properties you are looking for, and if not set default values.
myClass = function(options) {
this.foo = options.foo || 'foo';
this.bar = options.bar || 'bar';
};
customOptions = {
bar: 'foobar'
};
myInstance = new myClass(customOptions);

You could try something like this:
myClass = function(options){
var myOptions = {
foo: options.foo || 'foo',
bar: options.bar || 'bar'
};
};
If you are using jQuery you could also look at http://api.jquery.com/jQuery.extend/

Related

Is there a JS design pattern to combine N objects into 1 façade object and have code editors know which methods it has?

for example suppose I have:
var obj_a = {
foo: function() {}
}
var obj_b = {
bar: function() {}
}
How should I declare obj_c to have both methods so that typing obj_c. would popup foo and bar as valid autocomplete options?
I understand that you are looking for an IntelliSense equivalent, but if you need to create an obj_c which contains the properties of obj_a and obj_b, you can do so programmatically by using Object.assign:
const obj_c = Object.assign(obj_a, obj_b);
Working Example:
const obj_a = {
foo: function() {}
}
const obj_b = {
bar: function() {}
}
const obj_c = Object.assign({}, obj_a, obj_b)
console.log(obj_c);

Default enum value in javascript class constructor

I have a simple class, and I'm trying to figure out how to set a default value in the constructor:
var Foo = function(bar = Foo.someEnum.VAL1) {
this.bar = bar;
someEnum = {VAL1 : 1, VAL2: 2};
}
and to use it like:
var myFoo = new Foo(Foo.someEnum.VAL1);
but this is apparently wrong. What's the correct way to set a default enum value, or do I need to set the default to null, and check for the null in the constructor and set accordingly?
To clarify, bar is an enum for the Foo class. There are other properties in the class that are not shown. Also, updated class code.
You can try this if you want to make bar an optional parameter:
function Foo(bar) {
this.bar = bar || Foo.enum.VAL1; //If bar is null, set to enum value.
}
//Define static enum on Foo.
Foo.enum = { VAL1: 1, VAL2: 2, VAL3: 3 };
console.log(new Foo().bar); //1
console.log(new Foo(Foo.enum.VAL3).bar); //3
Do you just want bar to be defined inside the function?
var Foo = function() {
var bar = {VAL1 : 1, VAL2: 2};
}
or for a blank starting object:
var Foo = function() {
var bar = {};
}
Or are you wanting it to be set from a parameter that's passed into the function?
var Foo = function(barIn) {
var bar = barIn;
}
Another option - create the object (enum) from values passed in:
var Foo = function(val1, val2) {
var bar = {VAL1 : val1, VAL2: val2};
}
The possibilities go on, but it's not entirely clear what you're trying to achieve.
I'm not entirely sure what you are trying to do but maybe it is this...
var Foo = function (bar = 1) {
this.bar = bar;
}
Foo.VAL1 = 1;
Foo.VAL2 = 2;
Now you can do:
foo1 = new Foo();
alert(foo1.bar); //alerts 1;
foo2 = new Foo(Foo.VAL2);
alert(foo1.bar); //alerts 2;

Javascript constructor overriding

This a sample of function:
function User (name) {
this.options.name = name;
};
User.prototype.options = {
name: 'Default'
};
var foo = new User('foo');
var bar = new User('bar');
console.log( foo.options.name ); // 'bar'
console.log( bar.options.name ); // 'bar'
The question is, how to get 'foo' and 'bar'?
Thanks
When you add anything in a constructor's prototype, that will be shared by all the instances. It is the best thing for the functions, but may not be for the data. So, you want to construct the options objects in the constructor itself, like this
function User(name) {
this.options = {
name: name || "Default"
};
}
When you do like this, whenever an object of User is created, each object will get its own options object. So, changing the options with one object will not affect any other object's options.

Should an object belonging to an instance stay linked with the prototype?

What's the better?
This implementation
var Animal = function(){
this.properties = {};
for(var key in Animal.prototype.properties) this.properties[key] = Animal.prototype.properties[key];
};
Animal.prototype.properties = {
name: 'animal'
};
Or this one
var AnimalV2 = function(){
this.properties = Object.create(AnimalV2.prototype.properties);
};
AnimalV2.prototype.properties = {
name: 'animalv2'
};
When I change the prototype property it only affects the second implementation.
var dog = new Animal()
var cat = new AnimalV2();
Animal.prototype.properties.name = 'hello world';
AnimalV2.prototype.properties.name = 'hello world';
console.log(dog.properties.name); // 'animal'
console.log(cat.properties.name); // 'hello world'
As we can see dog.properties is no more linked with Animal.prototype.properties. Is it better in terms of performance or of code quality?
Well, in the first case
var Animal = function(){
this.properties = {};
for(var key in Animal.prototype.properties)
this.properties[key] = Animal.prototype.properties[key];
};
Animal.prototype.properties = {
name: 'animal'
};
You are iterating over all properties and assigning them one by one so it will cost more as more properties are in Animal.prototype.properties, in the second one:
var AnimalV2 = function(){
this.properties = Object.create(AnimalV2.prototype.properties);
};
AnimalV2.prototype.properties = {
name: 'animalv2'
};
You are creating a new object and assigning it's [[Prototype]] property to AnimalV2.prototype.properties, so it's only one assignement doesn't matter how many properties does AnimalV2.prototype.properties have.
TL;DR
So looking at performace and elegancy, the second one is the better way.
In case of clean code I don't like anyone of those, I preffer to have properties always on the constructor and keep the prototype for methods, it's just simple for non-javascript programmers. (and it will also be faster)
AnimalV3 = function() {
this.properties = {
prop1: 'a',
prop2: 'b'
};
}

Javascript prototype banals: inheritance

How can i override this.property at runtime and for each instance, without making a new class and eventually calling doAnotherThing on the parent?
var ThridPartyObject = function() {
this.property = 'value';
this.doOneThing= function() { /* */ }
this.doAnotherThing= function() { /* */ }
};
No luck with:
ThridPartyObject.prototype = {
property: 'myvalue',
doOneThing: function() { // Override only this function and call the other
return this.doAnotherThing();
}
};
EDIT: forgot to say that property may or may not exists.
I need this because, in backbone.js, i have to define a custom property for all my model instances, and some function should act in a different way of original backbone ones. Here is how backbone defines a Backbone.Model (_.extend is from underscore.js):
var Model = Backbone.Model = function(attributes, options) {
var defaults;
attributes || (attributes = {});
if (options && options.collection) this.collection = options.collection;
if (options && options.parse) attributes = this.parse(attributes);
if (defaults = getValue(this, 'defaults')) {
attributes = _.extend({}, defaults, attributes);
}
this.attributes = {};
this._escapedAttributes = {};
this.cid = _.uniqueId('c');
this.changed = {};
this._silent = {};
this._pending = {};
this.set(attributes, {silent: true});
// Reset change tracking.
this.changed = {};
this._silent = {};
this._pending = {};
this._previousAttributes = _.clone(this.attributes);
this.initialize.apply(this, arguments);
};
// Attach all inheritable methods to the Model prototype.
_.extend(Model.prototype, Events, {
// cut
});
If the object is truly "third party," and outside your control, then the creators of it have chosen a pattern that is not compatible with prototypal inheritance (sometimes called the "closure pattern"). You will not be able to override, globally, any properties of ThirdPartyObject instances, because every ThirdPartyObject gets property, doOneThing, and doAnotherThing newly assigned to it at construction time.
In this case the only solution would be to create a new factory function wrapping the original:
function modifiedThirdPartyObjectFactory() {
var x = new ThirdPartyObject();
x.property = "myvalue";
return x;
}
var mtpo = modifiedThirdPartyObjectFactory();
A pattern that does use prototypal inheritance would work as follows:
function ThirdPartyObject() {
this.property = "value";
}
ThirdPartyObject.prototype.doOneThing = function () {
};
ThirdPartyObject.prototype.doAnotherThing = function () {
};
This pattern sets instance properties, usually data, in the constructor. Whereas shared properties, usually methods, go on the prototype. The original code made all properties instance properties, so there are no shared properties you can modify that would result in your changes being reflected across all instances.
You're actually thinking about it backwards.
Prototype would be like the parent class.
It's not exactly-like the parent class in a class-based language (there are a LOT of differences).
But in this instance, for the sake of inheriting properties/methods, prototype would be the parent class.
When you make a Foo, Foo is the child, for all intent and purpose in your problem.
When you do this:
function Foo () { this.method = function () {}; this.property = {}; }
Foo.prototype.method = function () {};
Foo.prototype.property = {};
Foo.prototype.other_property = 3;
It's similar to saying:
PrototypeClass {
public virtual property = {};
public other_property = 3;
public virtual method ( ) { }
}
Foo inherits BaseClass {
public override property = {};
public override method () {}
}
var foo = new Foo();
The constructor for Foo is overriding everything up the chain in the prototype, that has the same name.
When Foo doesn't have a method or a property inside of it, THEN it looks upstream, through its inheritance/prototype chain.
So if you want to override methods/properties of Foo, then you MUST override the instance of new Foo().
Your options for that are pretty much just to build a wrapper around Foo... ...like:
function FooPlusPlus () {
var foo = new Foo();
foo.plus = function () { this.doSomething(); console.log(this.val); };
foo.plusPlus = function () { foo.plus(); console.log(this.other_val); };
return foo;
}
var fooPlusPlus = FooPlusPlus(); // ***NO NEW***
...or to create a function which simply extends a pre-existing object (whether it's a "class" or a "dictionary" or a function, or an array) with whatever added properties/functionality you want to extend them with:
var extendObj = function (subject, extensions) {
var key = "";
for (key in extensions) { if (extension.hasOwnProperty(key)) {
subject[key] = extensions[key];
}}
}
var regularFoo = new Foo();
extendObj(regularFoo, { awesomeFunc : function () { if (typeof this.doSomething === "function") { this.doSomething(); }}, coolProp : "Bob" });
JS gives you the freedom to let anything inherit anything, as long as you aren't expecting strings or numbers to act like classes with custom data, without careful manipulation of the Core objects.

Categories

Resources