Best way to set and get values of object in DOJO class - javascript

I have a class which takes in an object
{
a : "abc",
b : { z: 'as' }
c : 123
}
This class needs to provide getter and setter functions for the properties of the object.
What is the best way to do it?
Should I follow Java style and writer getA/setA / getB/setB functions, or can there be an easy function or Store which can do this ?

Julian Fondren's is a good answer, specially as it applies to JS in general and not only to DOJO.
In case you need setup getter and setter for a custom widget, you should use methods .get() and .set() from dijit/_widgetBase, below an example.
https://jsfiddle.net/f8pejjy4/2/
require([
"dojo/_base/declare",
"dijit/_WidgetBase",
"dojo/domReady!"
], function (declare, _WidgetBase) {
var YourWidget = declare(_WidgetBase, {
a: "",
_setAAttr: function (value) {
console.log("Sets value of a to " + value);
// some custom logic here
this._set('a', value);
},
_getAAttr:function(){
// some custom logic here
console.log("Return value");
return this.a;
},
});
var yourWidget = new YourWidget().placeAt(document.body);
yourWidget.startup();
yourWidget.set('a', 'another value');
yourWidget.get('a');
});

There's no need to use getA/setA functions.
var x = {
_a: "a",
set a(x) { this._a = x },
get a(x) { return this._a + "bc" },
b: { z: "as" },
get c() { return 123 }
}
console.log(x.a)
x.a = 'x'
console.log(x.a)
console.log(x.c)
x.c = 1
console.log(x.c)
Output:
abc
xbc
123
123
JavaScript's getters and setters have the advantage of working as an afterthought. When you decide you need them, you can add them, and the code can remain the same that had accessed and set the members of the object.
If the fake-private _a is unacceptable, you can make it actually private by having the getter and setter functions close over it:
var x = (function() {
var secret = 2
return {
get a() { return secret }
}
})()
/* no way to access 'secret' here */

Related

Javascript Know when object value is modified

For any variable or property thereof, is there a way to know when its value is set?
For example, say I have:
let x = { 'a': 1, 'b': 2 };
// x.a's set operation is linked to a method
x.a = 3; // the method is automatically called
Is there a way I can call a function when a's value is changed? Lots of code would be changing this value; I don't want to add the method call all over the place.
I'm aware of Proxies, but to use them seems to require a separate variable. Meaning, x can't be a proxy of itself.
Preferably this technique would work with primitive and non-primitives.
x can't be a proxy of itself
Sure it can. You can change the variable to point to a Proxy by simply doing
x = new Proxy(x, handler)
Primitive example:
const handler = {
set: function(obj, prop, value) {
console.log('setting prop: ', prop, ' to ', value)
obj[prop] = value;
return true;
}
};
let x = { 'a': 1, 'b': 2 };
x = new Proxy(x, handler);
x.a = 3; // the method is automatically called
To be honest, use Proxy if you can
If you really can't use Proxy, you could achieve this using using setters and getters
Though it does mean re-declaring your original x object, I assume it's declared inline like the Minimal, Complete and Verifiable Example in your question
let x = {
_a: 1,
_b: 2,
get a() {
return this._a;
},
get b() {
return this._b;
},
set a(value) {
console.log(`changing a from ${this._a} to ${value}`);
this._a = value;
},
set b(value) {
console.log(`changing b from ${this._b} to ${value}`);
this._b = value;
}
};
x.a = 3;

what does mean a 'get' statement in a function? [duplicate]

I've been trying to get my head around getters and setters and its not sinking in. I've read JavaScript Getters and Setters and Defining Getters and Setters and just not getting it.
Can someone clearly state:
What a getter and setter are meant to do, and
Give some VERY simple examples?
In addition to #millimoose's answer, setters can also be used to update other values.
function Name(first, last) {
this.first = first;
this.last = last;
}
Name.prototype = {
get fullName() {
return this.first + " " + this.last;
},
set fullName(name) {
var names = name.split(" ");
this.first = names[0];
this.last = names[1];
}
};
Now, you can set fullName, and first and last will be updated and vice versa.
n = new Name('Claude', 'Monet')
n.first # "Claude"
n.last # "Monet"
n.fullName # "Claude Monet"
n.fullName = "Gustav Klimt"
n.first # "Gustav"
n.last # "Klimt"
Getters and Setters in JavaScript
Overview
Getters and setters in JavaScript are used for defining computed properties, or accessors. A computed property is one that uses a function to get or set an object value. The basic theory is doing something like this:
var user = { /* ... object with getters and setters ... */ };
user.phone = '+1 (123) 456-7890'; // updates a database
console.log( user.areaCode ); // displays '123'
console.log( user.area ); // displays 'Anytown, USA'
This is useful for automatically doing things behind-the-scenes when a property is accessed, like keeping numbers in range, reformatting strings, triggering value-has-changed events, updating relational data, providing access to private properties, and more.
The examples below show the basic syntax, though they simply get and set the internal object value without doing anything special. In real-world cases you would modify the input and/or output value to suit your needs, as noted above.
get/set Keywords
ECMAScript 5 supports get and set keywords for defining computed properties. They work with all modern browsers except IE 8 and below.
var foo = {
bar : 123,
get bar(){ return bar; },
set bar( value ){ this.bar = value; }
};
foo.bar = 456;
var gaz = foo.bar;
Custom Getters and Setters
get and set aren't reserved words, so they can be overloaded to create your own custom, cross-browser computed property functions. This will work in any browser.
var foo = {
_bar : 123,
get : function( name ){ return this[ '_' + name ]; },
set : function( name, value ){ this[ '_' + name ] = value; }
};
foo.set( 'bar', 456 );
var gaz = foo.get( 'bar' );
Or for a more compact approach, a single function may be used.
var foo = {
_bar : 123,
value : function( name /*, value */ ){
if( arguments.length < 2 ){ return this[ '_' + name ]; }
this[ '_' + name ] = value;
}
};
foo.value( 'bar', 456 );
var gaz = foo.value( 'bar' );
Avoid doing something like this, which can lead to code bloat.
var foo = {
_a : 123, _b : 456, _c : 789,
getA : function(){ return this._a; },
getB : ..., getC : ..., setA : ..., setB : ..., setC : ...
};
For the above examples, the internal property names are abstracted with an underscore in order to discourage users from simply doing foo.bar vs. foo.get( 'bar' ) and getting an "uncooked" value. You can use conditional code to do different things depending on the name of the property being accessed (via the name parameter).
Object.defineProperty()
Using Object.defineProperty() is another way to add getters and setters, and can be used on objects after they're defined. It can also be used to set configurable and enumerable behaviors. This syntax also works with IE 8, but unfortunately only on DOM objects.
var foo = { _bar : 123 };
Object.defineProperty( foo, 'bar', {
get : function(){ return this._bar; },
set : function( value ){ this._bar = value; }
} );
foo.bar = 456;
var gaz = foo.bar;
__defineGetter__()
Finally, __defineGetter__() is another option. It's deprecated, but still widely used around the web and thus unlikely to disappear anytime soon. It works on all browsers except IE 10 and below. Though the other options also work well on non-IE, so this one isn't that useful.
var foo = { _bar : 123; }
foo.__defineGetter__( 'bar', function(){ return this._bar; } );
foo.__defineSetter__( 'bar', function( value ){ this._bar = value; } );
Also worth noting is that in the latter examples, the internal names must be different than the accessor names to avoid recursion (ie, foo.bar calling foo.get(bar) calling foo.bar calling foo.get(bar)...).
See Also
MDN get, set,
Object.defineProperty(), __defineGetter__(), __defineSetter__()
MSDN
IE8 Getter Support
You'd use them for instance to implement computed properties.
For example:
function Circle(radius) {
this.radius = radius;
}
Object.defineProperty(Circle.prototype, 'circumference', {
get: function() { return 2*Math.PI*this.radius; }
});
Object.defineProperty(Circle.prototype, 'area', {
get: function() { return Math.PI*this.radius*this.radius; }
});
c = new Circle(10);
console.log(c.area); // Should output 314.159
console.log(c.circumference); // Should output 62.832
(CodePen)
Sorry to resurrect an old question, but I thought I might contribute a couple of very basic examples and for-dummies explanations. None of the other answers posted thusfar illustrate syntax like the MDN guide's first example, which is about as basic as one can get.
Getter:
var settings = {
firstname: 'John',
lastname: 'Smith',
get fullname() { return this.firstname + ' ' + this.lastname; }
};
console.log(settings.fullname);
... will log John Smith, of course. A getter behaves like a variable object property, but offers the flexibility of a function to calculate its returned value on the fly. It's basically a fancy way to create a function that doesn't require () when calling.
Setter:
var address = {
set raw(what) {
var loc = what.split(/\s*;\s*/),
area = loc[1].split(/,?\s+(\w{2})\s+(?=\d{5})/);
this.street = loc[0];
this.city = area[0];
this.state = area[1];
this.zip = area[2];
}
};
address.raw = '123 Lexington Ave; New York NY 10001';
console.log(address.city);
... will log New York to the console. Like getters, setters are called with the same syntax as setting an object property's value, but are yet another fancy way to call a function without ().
See this jsfiddle for a more thorough, perhaps more practical example. Passing values into the object's setter triggers the creation or population of other object items. Specifically, in the jsfiddle example, passing an array of numbers prompts the setter to calculate mean, median, mode, and range; then sets object properties for each result.
Getters and setters really only make sense when you have private properties of classes. Since Javascript doesn't really have private class properties as you would normally think of from Object Oriented Languages, it can be hard to understand. Here is one example of a private counter object. The nice thing about this object is that the internal variable "count" cannot be accessed from outside the object.
var counter = function() {
var count = 0;
this.inc = function() {
count++;
};
this.getCount = function() {
return count;
};
};
var i = new Counter();
i.inc();
i.inc();
// writes "2" to the document
document.write( i.getCount());
If you are still confused, take a look at Crockford's article on Private Members in Javascript.
I think the first article you link to states it pretty clearly:
The obvious advantage to writing JavaScript in this manner is that you can use it obscure values that you don't want the user to directly access.
The goal here is to encapsulate and abstract away the fields by only allowing access to them thru a get() or set() method. This way, you can store the field/data internally in whichever way you want, but outside components are only away of your published interface. This allows you to make internal changes without changing external interfaces, to do some validation or error-checking within the set() method, etc.
Although often we are used to seeing objects with public properties without any access
control, JavaScript allows us to accurately describe properties. In fact, we can use
descriptors in order to control how a property can be accessed and which logic we can
apply to it. Consider the following example:
var employee = {
first: "Boris",
last: "Sergeev",
get fullName() {
return this.first + " " + this.last;
},
set fullName(value) {
var parts = value.toString().split(" ");
this.first = parts[0] || "";
this.last = parts[1] || "";
},
email: "boris.sergeev#example.com"
};
The final result:
console.log(employee.fullName); //Boris Sergeev
employee.fullName = "Alex Makarenko";
console.log(employee.first);//Alex
console.log(employee.last);//Makarenko
console.log(employee.fullName);//Alex Makarenko
You can define instance method for js class, via prototype of the constructor.
Following is the sample code:
// BaseClass
var BaseClass = function(name) {
// instance property
this.name = name;
};
// instance method
BaseClass.prototype.getName = function() {
return this.name;
};
BaseClass.prototype.setName = function(name) {
return this.name = name;
};
// test - start
function test() {
var b1 = new BaseClass("b1");
var b2 = new BaseClass("b2");
console.log(b1.getName());
console.log(b2.getName());
b1.setName("b1_new");
console.log(b1.getName());
console.log(b2.getName());
}
test();
// test - end
And, this should work for any browser, you can also simply use nodejs to run this code.
If you're referring to the concept of accessors, then the simple goal is to hide the underlying storage from arbitrary manipulation. The most extreme mechanism for this is
function Foo(someValue) {
this.getValue = function() { return someValue; }
return this;
}
var myFoo = new Foo(5);
/* We can read someValue through getValue(), but there is no mechanism
* to modify it -- hurrah, we have achieved encapsulation!
*/
myFoo.getValue();
If you're referring to the actual JS getter/setter feature, eg. defineGetter/defineSetter, or { get Foo() { /* code */ } }, then it's worth noting that in most modern engines subsequent usage of those properties will be much much slower than it would otherwise be. eg. compare performance of
var a = { getValue: function(){ return 5; }; }
for (var i = 0; i < 100000; i++)
a.getValue();
vs.
var a = { get value(){ return 5; }; }
for (var i = 0; i < 100000; i++)
a.value;
What's so confusing about it... getters are functions that are called when you get a property, setters, when you set it.
example, if you do
obj.prop = "abc";
You're setting the property prop, if you're using getters/setters, then the setter function will be called, with "abc" as an argument.
The setter function definition inside the object would ideally look something like this:
set prop(var) {
// do stuff with var...
}
I'm not sure how well that is implemented across browsers. It seems Firefox also has an alternative syntax, with double-underscored special ("magic") methods. As usual Internet Explorer does not support any of this.
I was also somewhat confused by the explanation I read, because I was trying to add a property to an existing prototype that I did not write, so replacing the prototype seemed like the wrong approach. So, for posterity, here's how I added a last property to Array:
Object.defineProperty(Array.prototype, "last", {
get: function() { return this[this.length - 1] }
});
Ever so slightly nicer than adding a function IMHO.
You can also use __defineGetter__:
function Vector2(x,y) {
this.x = x;
this.y = y;
}
Vector2.prototype.__defineGetter__("magnitude", function () {
return Math.sqrt(this.x*this.x+this.y*this.y);
});
console.log(new Vector2(1,1).magnitude)
Or, if you prefer:
function Vector2(x,y) {
this.x = x;
this.y = y;
this.__defineGetter__("magnitude", function () {
return Math.sqrt(this.x*this.x+this.y*this.y);
});
}
console.log(new Vector2(1,1).magnitude)
But this function has been flagged as "legacy" recently, being dropped in favor of Object.defineProperty().
There's no example here with ES6 class (which is not even 'new' now, it's the norm):
class Student {
contructor(firstName, lastName){
this.firstName = firstName
this.lastName = lastName
this.secretId = Math.random()
}
get fullName() {
return `${this.firstName} ${this.lastName}`; // this is backtick in js, u can check it out here: https://stackoverflow.com/a/27678299/12056841
}
set firstName(newFirstName) {
// validate that newFirstName is a string (and maybe limit length)
this.firstName = newFirstName
}
get studentId() { return this.secretId }
}
and no setter for secretId because we don't want anyone to change it.
** if secretId shouldn't be changed at all, a nice approach is to declare it as 'private' to this class by adding a '#' to it
(e.g: this.#secretId = Math.random(), and return this.#secretId
Update: about backing fields
You might need to rename your field - or your setter function but it makes more sense to me to change your field name. One option is like I mentioned above (using a # for declaring the field as 'private'). Another way is to just rename it (_firstName, firstName_...)
I've got one for you guys that might be a little ugly, but it does get'er done across platforms
function myFunc () {
var _myAttribute = "default";
this.myAttribute = function() {
if (arguments.length > 0) _myAttribute = arguments[0];
return _myAttribute;
}
}
this way, when you call
var test = new myFunc();
test.myAttribute(); //-> "default"
test.myAttribute("ok"); //-> "ok"
test.myAttribute(); //-> "ok"
If you really want to spice things up.. you can insert a typeof check:
if (arguments.length > 0 && typeof arguments[0] == "boolean") _myAttribute = arguments[0];
if (arguments.length > 0 && typeof arguments[0] == "number") _myAttribute = arguments[0];
if (arguments.length > 0 && typeof arguments[0] == "string") _myAttribute = arguments[0];
or go even crazier with the advanced typeof check: type.of() code at codingforums.com

Why doesn't JavaScript ES6 support multi-constructor classes?

I want to write my Javascript class like below.
class Option {
constructor() {
this.autoLoad = false;
}
constructor(key, value) {
this[key] = value;
}
constructor(key, value, autoLoad) {
this[key] = value;
this.autoLoad = autoLoad || false;
}
}
I think it would be nice if we can write out class in this way.
Expect to happen:
var option1 = new Option(); // option1 = {autoLoad: false}
var option2 = new Option('foo', 'bar',); // option2 = {foo: 'bar'}
var option3 = new Option('foo', 'bar', false); // option3 = {foo: 'bar', autoLoad: false}
I want to write my Javascript class like below
You can't, in the same way you can't overload standard functions like that. What you can do is use the arguments object to query the number of arguments passed:
class Option {
constructor(key, value, autoLoad) {
// new Option()
if(!arguments.length) {
this.autoLoad = false;
}
// new Option(a, [b, [c]])
else {
this[key] = value;
this.autoLoad = autoLoad || false;
}
}
}
Babel REPL Example
Of course (with your updated example), you could take the approach that you don't care about the number of arguments, rather whether each individual value was passed, in which case you could so something like:
class Option {
constructor(key, value, autoLoad) {
if(!key) { // Could change this to a strict undefined check
this.autoLoad = false;
return;
}
this[key] = value;
this.autoLoad = autoLoad || false;
}
}
What you want is called constructor overloading. This, and the more general case of function overloading, is not supported in ECMAScript.
ECMAScript does not handle missing arguments in the same way as more strict languages. The value of missing arguments is left as undefined instead of raising a error. In this paradigm, it is difficult/impossible to detect which overloaded function you are aiming for.
The idiomatic solution is to have one function and have it handle all the combinations of arguments that you need. For the original example, you can just test for the presence of key and value like this:
class Option {
constructor(key, value, autoLoad = false) {
if (typeof key !== 'undefined') {
this[key] = value;
}
this.autoLoad = autoLoad;
}
}
Another option would be to allow your constructor to take an object that is bound to your class properties:
class Option {
// Assign default values in the constructor object
constructor({key = 'foo', value, autoLoad = true} = {}) {
this.key = key;
// Or on the property with default (not recommended)
this.value = value || 'bar';
this.autoLoad = autoLoad;
console.log('Result:', this);
}
}
var option1 = new Option();
// Logs: {key: "foo", value: "bar", autoLoad: true}
var option2 = new Option({value: 'hello'});
// Logs: {key: "foo", value: "hello", autoLoad: true}
This is even more useful with Typescript as you can ensure type safety with the values passed in (i.e. key could only be a string, autoLoad a boolean etc).
Guessing from your sample code, all you need is to use default values for your parameters:
class Option {
constructor(key = 'foo', value = 'bar', autoLoad = false) {
this[key] = value;
this.autoLoad = autoLoad;
}
}
Having said that, another alternative to constructor overloading is to use static factories. Suppose you would like to be able to instantiate an object from plain parameters, from a hash containing those same parameters or even from a JSON string:
class Thing {
constructor(a, b) {
this.a = a;
this.b = b;
}
static fromHash(hash) {
return new this(hash.a, hash.b);
}
static fromJson(string) {
return this.fromHash(JSON.parse(string));
}
}
let thing = new Thing(1, 2);
// ...
thing = Thing.fromHash({a: 1, b: 2});
// ...
thing = Thing.fromJson('{"a": 1, "b": 2}');
Here's a hack for overloading based on arity (number of arguments). The idea is to create a function from a number of functions with different arities (determined by looking at fn.length).
function overloaded(...inputs) {
var fns = [];
inputs.forEach(f => fns[f.length] = f);
return function() {
return fns[arguments.length].apply(this, arguments);
};
}
var F = overloaded(
function(a) { console.log("function with one argument"); },
function(a, b) { console.log("function with two arguments"); }
);
F(1);
F(2, 3);
Of course this needs a lot of bullet-proofing and cleaning up, but you get the idea. However, I don't think you'll have much luck applying this to ES6 class constructors, because they are a horse of a different color.
you can use static methods,look at my answer to same question
class MyClass {
constructor(a,b,c,d){
this.a = a
this.b = b
this.c = c
this.d = d
}
static BAndCInstance(b,c){
return new MyClass(null,b,c)
}
}
//a Instance that has b and c params
MyClass.BAndCInstance(b,c)
Use object.assigne with arguments with this
This={...this,...arguments}
Its not the overload I wanted, but this is a basic version of how I faked my way through creating an obj1 with some different initialization behavior. I realize I could have expanded the arguments as stated above, but I already had a nasty set of arguments and relatively different data sources to deconstruct that would have really distorted my objectives; this just made it cleaner for my situation...
class obj1{
constructor(v1, v2){
this.a = v1;
this.b = v2;
}
}
class obj1Alt{
constructor(v1, v2){
return new obj1(v1*2,v2*2);
}
}
new obj1(2,4) // returns an obj1
new obj1Alt(2,4) // also returns an obj1
Disclaimer: I've been programming for a long time, but I am fairly new to JS; probably not a best practice.

Set undefined javascript property before read

var tr={};
tr.SomeThing='SomeThingElse';
console.log(tr.SomeThing); // SomeThingElse
console.log(tr.Other); // undefined
tr.get=function(what){
if (tr.hasOwnProperty(what)) return tr[what];
else return what;
};
tr.get('SomeThing') // SomeThingElse
tr.get('Other') // Other
Is there any way to make tr.Other or tr['Other'] and all other undefined properties of the object to return its name instead undefined?
Three solutions:
Implement your object as a Proxy, which is designed to do exactly what you want. Yet, it is only a draft and currently only supported in Firefox' Javascript 1.8.5 It was standardised with ES6, but might not yet be available in all environments.
Always fill your translation object with a complete set of messages. When creating that "dictionary" (serverside or clientside), always include all needed keys. If no translation exists, you can use a fallback language, the message's name or the string representation of undefined - your choice.
But a non-existing property should always mean "there is no such message" instead of "no translation available".
Use a getter function with a string parameter instead of object properties. That function can look the messages up in an internal dictionary object, and handle misses programmatically.
I would recommend a map object which is different from the dictionary, to allow "get" and co as message names:
var translate = (function(){
var dict = {
something: "somethingelse",
...
};
return {
exists: function(name) { return name in dict; },
get: function(name) { return this.exists(name) ? dict[name] : "undefined"; },
set: function(name, msg) { dict[name] = msg; }
};
})();
You could define a getter for your property, either using object initializers:
var o = {
a: 7,
get b() {
return this.a + 1;
},
set c(x) {
this.a = x / 2;
}
};
console.log(o.a); // 7
console.log(o.b); // 8 <-- At this point the get b() method is initiated.
o.c = 50; // <-- At this point the set c(x) method is initiated
console.log(o.a); // 25
or using Object.defineProperties():
var o = { a: 0 };
Object.defineProperties(o, {
'b': { get: function() { return this.a + 1; } },
'c': { set: function(x) { this.a = x / 2; } }
});
o.c = 10; // Runs the setter, which assigns 10 / 2 (5) to the 'a' property
console.log(o.b); // Runs the getter, which yields a + 1 or 6
While this solution isn't exactly what you were looking for, a JavaScript implementation of python's collections.defaultdict class might help:
var collections = require('pycollections');
var dd = new collections.DefaultDict([].constructor);
console.log(dd.get('missing')); // []
dd.get(123).push('yay!');
console.log(dd.items()); // [['missing', []], [123, ['yay!']]]

Neat alternatives to __defineGetter__?

Getters and setters are a beauty in VB.Net:
Get
Return width
End Get
Set(ByVal value As Integer)
width = value
End Set
In Javascript, this is probably what we would do:
function Test() {
var width = 100;
this.__defineGetter__("Width", function() {
return width;
});
this.__defineSetter__("Width", function(value){
width = value;
});
}
It looks like a plate of spaghetti ransacked by a kuri. What are some neater alternatives we have?
Note: The new code should access the value using new Test().Width and not new Test().Width().
With ES5 you'll be able to do:
function Test() {
var a = 1;
return {
get A() { return a; },
set A(v) { a = v; }
};
}
The getter/setter functions can of course do anything you want them to.
Here's a clean(er) alternative (also for older script engines):
function Test() {
var a=1;
return { A: { toString: function(){return a;} } };
}
alert(Test().A); //=> 1
Mind you, you can't use it to define private/static complex structures. You can only 'get' strings or numbers (so immutable variables) with this pattern. Maybe the pattern can be enhanced using json.
[edit] Using json, you can also create a getter this way for objects:
function Test() {
var a=1,
b = {foo:50, bar:100};
return {
A: { toString: function(){return a;} }
foobar: { toString: function(){return JSON.stringify(b);} }
};
}
var foobar = JSON.parse(Test().foobar);
alert(foobar.foo); //=> 50
In Ecmascript5, the 'clean' (and standards compliant) way of doing this is with defineProperty.
function Test() {
var a = 1;
Object.defineProperty(this, "A", {get : function() {
return a;
},
enumerable : true});
}
This assumes that you just want to see how to define a getter. If all you want to do is make instances of Test immutable (a good thing to do where you can), you should use freeze for that:
function Test() {
this.a = 1;
Object.freeze(this);
}

Categories