I have a JS object that contains base options. If that object is initialized with a specific new option, I only want to change the one that was specified.
//Object :
var controller = function (){
var _id = id;
var _options = {
placeholder: "Search..."
value: "Some text",
width: 25,
...
};
// ==================================
// Public Functions
// ==================================
return {
init: function (id, options = null) {
...
}
}
}();
Example here i only change the placeholder property.
Call: controller.init('demo', options = { placeholder: 'Other value...' });
Expected change:
_options = {
placeholder: "Other value..."
value: "Some text",
width: 25,
...
};
You can use ... to merge the provided options into the default options.
var controller = function() {
var _id = id;
var _options = {
placeholder: "Search..."
value: "Some text",
width: 25,
// ...
};
// ==================================
// Public Functions
// ==================================
return {
init: function(id, options = {}) {
this.options = {..._options, ...options};
// ...
}
}
}();
You can use the below code.
_options = Object.assign(_options, options);
Here, _options will have default properties and values. options is input property with limited configuration. So, From this code, _options get only overuse with options properties.
Hope it's useful.
Object assign works too.
const thingy = (() => {
let myWords = {
favorite: "defenestrate",
leastFavorite: "whilst",
newest: "copacetic",
oldest: "dada",
};
return (words) => {
myWords = Object.assign(myWords, words);
console.log(JSON.stringify(myWords));
}
})();
// For the demo.
thingy({newest: "pyroclastic", fakest: "supercalifragilisticexpialidocious"});
Related
Is there a way to optionally declare dots: {} from inside Object.create?
As you can see I have tried
standard default parameter assignment
tried using a nullish coalescing
Neither work.
Any guidance would be appreciated.
'use strict'
let Carousel = function(name, dots=true) {
this.name = name
this.dots = dots ?? true
}
Carousel.prototype.show = function() {
console.log(`${this.name} and ${this.dots}`)
}
window.addEventListener('DOMContentLoaded', () => {
let usps = Object.create(Carousel.prototype, {
name: { value: 'element name', writeable: false}
// dots: { value: true, writeable: false }
})
usps.show()
})
Not sure why you don't use new keyword and instead create object from prototype, but in either case, if you set default value to prototype of your object, you will get dots on it.
let Carousel = function(name, dots) {
this.name = name
this.dots = dots
}
Carousel.prototype.show = function() {
console.log(`${this.name} and ${this.dots}`)
}
Carousel.prototype.dots = true;
window.addEventListener('DOMContentLoaded', () => {
let usps = Object.create(Carousel.prototype, {
name: { value: 'element name', writeable: false},
})
usps.show() // will show that dots equals true
let usps2 = Object.create(Carousel.prototype, {
name: { value: 'element name', writeable: false},
dots: { value: false, writeable: false }
});
usps2.show(); // will show that dots equals false
})
It is important, that if you will want to use new operator, you will have to modify your constructor, so if there is no dots parameter set, you will not override one with undefined:
let Carousel = function (name, dots) {
this.name = name;
if (dots !== undefined) {
this.dots = dots;
}
};
Carousel.prototype.show = function () {
console.log(`${this.name} and ${this.dots}`);
};
Carousel.prototype.dots = true;
window.addEventListener("DOMContentLoaded", () => {
let usps = new Carousel("element name");
usps.show();
let usps2 = new Carousel("element name 2", false);
usps2.show();
});
Here is the my question
var panel = {
_pnlHeaderContainer: $('.panelHeader'),
_pnlHeaderString:"",
//private method
_Write: function (pnlHeaderString) { return this._pnlHeaderContainer.html(pnlHeaderString); },
Clear: function () { return this._pnlBaslikContainer.html(""); },
// _fake:this,
Header: {
AddEvent:"Add Event",
Calendar: "Calendar",
}
};
what I wanna achieve is using the _Write method in Header object
something like this
Header: {
AddEvent:this._Write("Add Event"),
Calendar: "Calendar",
}
trying to run this code like this panel.Header.AddEvent; but it says me Write is not a function
I like to provide a context when creating a class
function Panel(){
var context = this;
this._pnlHeaderContainer = $('.panelHeader');
this._pnlHeaderString = "";
this._Write = function(pnlHeaderString){
return context._pnlHeaderContainer.html(pnlHeaderString);
};
this.Clear = function(){
return context._pnlBaslikContainer.html("");
};
this.Header = {
AddEvent: function(){ return context._Write("Add Event"); },
Calendar: "Calendar",
};
}
var panelObject = new Panel();
// Do whatever you want...
panelObject.Header.AddEvent();
I'd like to create a Javascript object that can save and load its state (to local storage).
This is the basic pattern I'm using:
var obj = function () {
// private members
//
return {
// public members
load: function () {
this.state = JSON.parse(localStorage.getItem('obj'));
if (this.state === null) {
this.state = {
name: 'foo'
};
}
},
save: function () {
localStorage.setItem('obj', JSON.stringify(this.state));
}
};
}();
// load state
obj.load();
console.log(obj.state.name);
// save state
obj.state.name = 'bar';
obj.save();
But there's one thing that annoys me about this pattern: I have to access the object's persistent properties through the 'state' property.
How can I rewrite this so I can use the object in a more natural way, like:
// load state
obj.load();
console.log(obj.name);
// save state
obj.name = 'bar';
obj.save();
This is a very simple 'state', but the solution has to work for a complex state object with nested objects, arrays etc., so simply adding a 'name' property to my object is not what I'm after.
If you don't care which properties get loaded/saved then you can simply copy all from state into self. For example, after reading into var state (instead of this.state since you don't want state to be a part of this anymore): for(x in state) this[x] = state[x];
similarly, you'd save out: var state = {}; for(x in this) state[x] = this[x]
However, if you want to have a pre-defined list, then I'd recommend: var fields = ['name', 'zip', 'age'];
And then use for(x in fields) this[x] = state[x] to load and for(x in fields) state[x] = this[x]; to save.
Sorry it's a bit pieced together, but I hope you can follow what I mean :)
EDIT: Added full example per OPs request.
An example of a full solution using this technique is as follows:
var obj = function () {
// private members
//
return {
// public members
load: function () {
var state = JSON.parse(localStorage.getItem('obj'));
if(state == null) state = { name: 'foo' };
for(x in state) this[x] = state[x];
},
save: function ()
{
var state = {};
// check if it's a function. This version taken from underscorejs
var isFunction = function(obj) {
return !!(obj && obj.constructor && obj.call && obj.apply);
};
for(x in this)
{
if(isFunction(this[x])) continue; // skip functions
state[x] = this[x];
}
localStorage.setItem('obj', JSON.stringify(state));
}
};
};
You can also accomplish a direct save when a property changes,
by using ES5 getters/setters or by using Watch.js
Watch.js example:
var obj = (function () {
// private members
//
var self = {
// Some properties
name: '',
otherName: '',
// Try to load state or use "foo state"
state: JSON.parse(localStorage.getItem('obj')) || {
name: 'foo'
},
save: function () {
localStorage.setItem('obj', JSON.stringify(this.state));
}
};
// Watch the object and save it to local storage, when a property changes
// (Of course, you don't need to call the save method here...)
watch(self, function(property, value) {
console.log('saving state!');
self.state[property] = value;
self.save();
});
return self;
}());
// Update some properties and see that it is saved to local storage.
obj.name = "Some name";
obj.otherName = "Some other name";
console.log(JSON.parse(localStorage.getItem('obj')));
Example on JsFiddle.
You could make the state internal and surface getters and setters:
var obj = function () {
// private members
var state = {};
return {
// public members
load: function () {
var loadedState = JSON.parse(localStorage.getItem('obj'));
if (loadedState === null) {
state = {
name: 'foo'
};
} else {
state = loadedState;
}
},
save: function () {
localStorage.setItem('obj', JSON.stringify(state));
},
getState: function (key) {
return state[key];
},
setState: function (key, value) {
state[key] = value;
}
};
};
Using jQuery's extend():
var obj = (function () {
return {
load: function () {
var stored = localStorage.getItem("obj");
var state = stored ? JSON.parse(stored) : {
name: 'foo'
};
$.extend(this, state);
},
save: function () {
localStorage.setItem("obj", JSON.stringify(this));
}
};
})();
// load state
obj.load();
console.log(obj);
// save state
obj.name = 'bar';
obj.save();
jsfiddle
All credit to pimvdb.
I am trying to create a js object, I want either the user passes in some json data or the objects properties are set by default as shown below. After that is all set, I finally want to call an init function that runs and does the work. Thanks for any help. I am not trying to create a jQuery plugin.
var PictureDialog = function (settings) {
settings = {
allowShortKey: true,
prevID: null,
prevCounterNumber: null,
startValue: 0,
nextValue: 1,
init: function() {
//Do work
//Show dialog
}
},settings;
}
Would the call look something like this
PictureDialog({prevID:1}).init();
Not sure why you would need an init function at all. This is how I would do it:
(function () {
var defaultSettings = {
allowShortKey: true,
prevID: null,
prevCounterNumber: null,
startValue: 0,
nextValue: 1
};
PictureDialog = function (settings) {
settings = settings || defaultSettings;
//Do work
//Show dialog
};
})();
The outer function is just to make sure that defaultSettings doesn't pollute the global scope.
If I understand correctly you want to set some default values, with the help of jQuery you can use $.extend like this:
function Foo( settings ) {
var _defaults = { a: 'a', b: 'b' };
settings = $.extend( settings, _defaults );
}
With pure JavaScript you'd have to do something like this:
function Foo( settings ) {
var _defaults = { a: 'a', b: 'b' };
settings.a = settings.a || _defaults.a;
settings.b = settings.b || _defaults.b;
}
As for the init method, you can just add it to the prototype and execute it in the constructor so you don't even have to call it when you create a new instance:
function Foo( settings ) {
var _defaults = { a: 'a', b: 'b' };
...
this.init();
}
Foo.prototype = {
init: function() {
console.log('initialized!');
}
}
The quick and simple way would be this:
var PictureDialog = function (settings)
{
settings = {
allowShortKey: true,
prevID: null,
prevCounterNumber: null,
startValue: 0,
nextValue: 1,
init: function()
{
//Do work
//Show dialog
return this;//<--return object, too
}
};
return settings;//return the object
};
foo = PictureDialog().init();//the init will be called on the return value of PictureDialog
I don't, however, get why the PictureDialog function expects a settings argument. Either pass nothing to the function at all, or alter the passed value:
var PictureDialog = (function()
{
var defaults = {
allowShortKey: true,
prevID: null,
prevCounterNumber: null,
startValue: 0,
nextValue: 1,
init: function()
{
//Do work
//Show dialog
return this;//<--Very important
};
return function (settings)
{
settings = settings instanceof Object ? settings : {};
for (var n in defaults)
{
if (defaults.hasOwnProperty(n))
{//set all properties that are missing from argument-object
settings[n] = settings[n] || defaults[n];
}
}
return settings;
};
}());
foo = PictureDialog({allowShortKey: false}).init();//will return full settings object
I'm using Node.js and am creating some models for my different objects. This is a simplified version of what they look like at the moment.
var Foo = module.exports = function () {
var values = { type: 'foo', prop1: '', prop2: '' };
function model() {}
model.init = function(val) {
_.extend(values, val);
return model;
}
model.store = function(cb) {
db.insert(values.type, values, cb);
}
model.prop1 = function(val) {
if(!arguments.length) return values.prop1;
values.prop1 = val;
return model;
}
return model;
}
Then I can do:
var foo = Foo();
foo.init({prop1: 'a', prop2: 'b'}).store(function(err) { ... });
A lot of the functions, like model.init and model.store are going to be identical for every model, but they depend on local variables in the closure like values.
Is there a way to pull these functions into a base class that I can then extend each of models with instead of duplicating all of this code? I would like to end up with something like this, but I'm not sure what the base class should look like or the right way to use it to extend Foo.
var Foo = module.exports = function () {
var values = { type: 'foo', prop1: '', prop2: '' };
function model() { this.extend(base); }
model.prop1 = function(val) {
if(!arguments.length) return values.prop1;
values.prop1 = val;
return model;
}
return model;
}
Yes you could do something like this;
model.js
/** require your db and underscore varialbles etc.. **/
module.exports = function(values, base) {
var model = typeof base == 'function' ? base : function() {};
model.init = function(val) {
_.extend(values, val);
return model;
}
model.store = function(cb) {
db.insert(values.type, values, cb);
}
return model;
}
then the usage would be similar to;
var Foo = module.exports = function () {
var values = { type: 'foo', prop1: '', prop2: '' };
var model = require('/path/to/model.js')(values);
model.prop1 = function(val) {
if(!arguments.length) return values.prop1;
values.prop1 = val;
return model;
}
return model;
}
If you need to extend the constructor
var Foo = module.exports = function () {
var values = { type: 'foo', prop1: '', prop2: '' },
model = function() { ...something here... };
require('/path/to/model.js')(values, model);
model.prop1 = function(val) {
if(!arguments.length) return values.prop1;
values.prop1 = val;
return model;
}
return model;
}