Benefit of using 'set' in a property of a object? - javascript

I'm working on a Codecademy course and have written the following code that works:
let person = {
_name: 'Lu Xun',
_age: 137,
set age (newAge) {
if (typeof newAge === 'number'){
this._age= newAge;
} else {
console.log('Invalid input');
}
}
}
person.age= 22;
console.log(person['_age']);
I was getting my head around how the set works and thought that it essentially worked the same as defining a method within the person object just with different syntax.
So I tried it out, called the age method passing 22 to it from outside the object using the normal way you would call a method. It worked the same. See below.
let person = {
_name: 'Lu Xun',
_age: 137,
age: function (newAge) {
if (typeof newAge === 'number'){
this._age= newAge;
} else {
console.log('Invalid input');
}
}
}
person.age(22);
console.log(person['_age']);
What are the benefits of using the 'set' syntax? ie why use it when a normal function/method definition works in the same way?

Imagine you wrote a very huge code and a lot of them access a variable like this:
// The object
const person = { age: 12 }
// You access it very often
console.log(person.age);
Now you certainly want to calculate the age based on the birthdate. With a method, you would have to replace person.age with person.getAge() everywere you use it. That can take time. With getters / setters you can just replace one single line and everything keeps working.
If you don't think that this is a problem, you might wanna look at this java thread. Java doesnt have getters / setters.

The get/set syntax is for a property whereas using a method is just that, a method. Most of the time a simple public variable will suffice however there are times, like in your example that you want to validate the input to ensure that it meets whatever expectations you have of the value.
Also consider how your code will be called and what that will look like. If you were to use a function to change the value and a function to get the value your code will look something like this:
var myObject = new CoolObject('some parameter');
myObject.setComment('this is a super cool comment');
console.log(myObject.getComment());
Where as if you implemented the get/set functions on your property it will look like this
var myObject = new CoolObject('some parameter');
myObject.comment = 'This is a super cool comment';
console.log(myObject.comment);
At the end of the day it really doesn't matter as both code snippets will do the exact same thing however one reads easier and wont get you yelled at by your co-workers. Keep in mind the second example doesn't change if you simply expose a public variable.

Related

In which way can i pass through a method call in JavaScript class

Assume we have some classes A and B:
Class A {
constructor(a) {
this.a = a;
};
showInfo() {
console.log(this.a)
};
};
Class B {
constructor(b) {
this.b = b;
};
printText() {
console.log('its B!');
};
};
Then we create an instance of B like this:
const objB = new B(
new A(3)
);
So now we have objB with its own method inside - printText, and we surely can call it.
But what if i want somehow when calling not existing method in objB to make it pass through to encapsulated A class in there and look for invoking this method on him, like this: objB.showInfo() - to give me 3 here ?
Same story, but at this time i want when calling not existing method on A to make it pass through to B outside (like that printText)?
P.S. Don't wanna use super() and inheritance, just composition and wrapping objects, hope you've got the point.
Just a little warning at the start: this might make your program harder to debug, and it also might be a little complicated for something like this. As others have suggested, you should probably investigate other options which may be simpler and also less in the way of everything else your code does.
Here's the code which provides the functionality:
function makeGetProxy(t){
return new Proxy(t, {
get(obj,prop){
if(prop in t){
return t[prop];
}else{
var keys = Object.keys(obj);
for (var i = 0; i < keys.length; i++) {
var val = t[keys[i]];
if(prop in val){
return val[prop];
// what about a recursive function?
}
}
return undefined;
}
}
});
}
And one itty bitty change to your constructor in B:
class B {
constructor(b) {
this.b = b;
return makeGetProxy(this);
};
printText() {
console.log('its B!');
};
};
If you want, you can also do the same to A.
Let's slow down. What just happened? I'll explain.
Since the properties we might request don't already exist, we're going to have to use a getter (see resources) to properly send back the value required. But, since we don't know the property names, we need a Proxy (see resources) to have a "catch-all" kind of get method.
The proxy will check if the property requested prop already exists, and if so, returns it. If it doesn't exist, it checks all of your properties' properties (all of the sub-properties).
The first result it gets, it returns it. This might cause unexpected bugs in your program. If it doesn't find it, it simply returns undefined.
Then, the proxy is generalized into a function for reuse in multiple classes (as you requested).
So, this can get the properties of a class and the properties of a class' properties, but if you need to go further (with your C class that doesn't exist yet), you can use a recursive function. I currently don't have the implementation for that recursive function, but in my head it would comprise mostly of a modified version of the else block in the makeGetProxy function.
Again, be careful with this code. It might get in the way of other things and cause unnecessary difficulty in debugging.
Resources:
Getters (MDN)
Proxy (MDN)
I borrowed some code from this answer and got the Proxy idea from this answer.

What's the point of a JavaScript getter method?

I'm trying to understand what the advantage is, if any, of the following:
const obj = {
forename: 'Foo',
surname: 'Bar',
get name() {
//yes I get that I can do other stuff here
return this.forename+' '+this.surname;
}
}
alert(obj.name); //Foo Bar
...over...
const obj = {
forename: 'Foo',
surname: 'Bar',
name() {
return this.forename+' '+this.surname;
}
}
alert(obj.name()); //Foo Bar
I've read around (1; 2; 3) but can't seem to see any benefit beyond readability and code style. Is that all it is? No implicit behavioural changes between the two methods?
Is it with one eye on future class property/method visibility in JavaScript? That would make sense - getters for private properties. But since that's not here yet, I can't see the point of the above.
Can anyone enlighten me?
One difference is typeof will actually work as expected when using a getter, that is, it will return the actual type of the primitive returned by the getter, while using a method will always return function:
const objGetter = {
forename: 'Foo',
surname: 'Bar',
get name() {
return `${ this.forename } ${ this.surname }`;
}
}
const objGetterLogic = {
forename: undefined,
surname: 'Bar',
get name() {
return this.forename ? this.surname : 3;
}
}
const objMethod = {
forename: 'Foo',
surname: 'Bar',
name() {
return `${ this.forename } ${ this.surname }`;
}
}
console.log(`objGetter`, typeof objGetter.name);
console.log(`objMethod`, typeof objMethod.name);
console.log(`objGetterLogic (without forename)`, typeof objGetterLogic.name);
objGetterLogic.forename = 'Alice';
console.log(`objGetterLogic (with forename)`, typeof objGetterLogic.name);
Of course, you can call name() in the version with the method, but with the getter that will work transparently.
Also, if you have nested getters, you can call them transparently, which is something that comes in handy if you are navigating an object programmatically, as otherwise, you would need to account for the possibility of properties being either a value or a function that needs to be called to get the actual value you need:
class Shape {
constructor(type, children) {
this.type = type || '';
this.children = children || [];
}
get firstChild() {
return this.children[0];
}
get lastChild() {
return this.children[this.children.length - 1];
}
}
const group1 = new Shape('group1', [
new Shape('a'),
new Shape('b'),
new Shape('c'),
]);
const group2 = new Shape('group2', [
new Shape('d'),
new Shape('e'),
new Shape('f'),
]);
const group4 = new Shape('group4', [
group1,
group2,
]);
console.log(group4.firstChild.lastChild.type);
In any case, I think one of the greatest advantages of getters and setters are just increased readability and reduced verbosity, even though that usually comes down to personal preference anyway. In any case, I rather use:
person.name = 'Alice Smith';
Than:
person.setName('Alice', 'Smith');
But we could also argue the latter might be more appropriate in some cases.
Since you defined just a getter for name, without defining a setter, if you attempt to change its value, for example obj.name = "foo", nothing is going to happen.
On the other hand, if you try to change your name property on your second object, nothing will stop you by doing so.
Since the capabilities of these two features are identical, we need to consider the readability and writeability of code that interacts with such a property (or method).
The entire advantage is the ability to run functions when accessing a property. "Ah," you say, "but if I wanted to run a function, I'd just use a function." And you'd be correct -- as I say initially -- that the two have no difference in terms of capabilities. But accessing a property is different from calling a function for the person writing code that interacts with your object.
Sylistically, I expect accessor methods to have names that start with get. Your example function called name seems poor style to me, whereas a property called name seems much better. If you ask me what advantage obj.getName() has over obj.name I can readily tell you the latter is much shorter to type! There are corresponding readability concerns with setters: obj.setBirthday(new Date(...)) versus a setter property, obj.birthday = new Date(...) (suppose, e.g., that this mutates a corresponding age property)
That's it -- all languages are designed to make a Turing-complete set of functionality more comprehensible to human authors and readers. If a feature doesn't help you achieve that goal, don't use it!
As a syntactic sugar it can be useful to make your code if not more readable then at least less clogged: x = a().b().c().d() vs x = a.b.c.d
Suppose you already have a code like that obj.attr... a lot of code like that, and at some point you realize that you need a function instead of access operator in all these places Get/set to the rescue. Especially useful in debug to catch a property access. And even more so if you have to work with code you have no control over
Sometimes using getter is more idiomatic. Reader expects that obj.attr has no side effects, but he is not so sure if he sees a function

Javascript, convenience method for calling super class method from overwritten method

In order to emulate classical, Java-like classes in JavaScript I have a function called
"createClass":
It has 3 arguments:
* Name and path of the constructor function, that should be created.
* Path of the superclass.
* JavaScript object with methods of the class.
For example:
myApp.createClass("myapp.core.JString", "myapp.core.BaseString", {
abc: function () {
...
First I create a constructor function
Cf = function () {
...
If there is a super class ("Base" is the constructor function of the super class):
protoObj = new Base();
protoObj.constructor = Cf;
Now, method by method of the new class, I put them on to the protoObj:
("protos" is the object with the "class" methods)
for (name in protos) {
????????????????????
protoObj[name] = protos[name]
But before putting the methods to the protoObj, I want to create convenience methods for
calling superclass methods from overwritten methods:
init: function () {
this.jstring_super_init();
...
So, where the question marks are, I want to place the following code:
(classnameLast in this case is "jstring" => last part of class path => lowercase)
if ((typeof protos[name] === "function") &&
(protoObj[name]) &&
(typeof protoObj[name] === "function")) {
supername = classnameLast + "_super_" + name;
protoObj[supername] = XXXXXXXXXXXXX
In the place, where the multiple X are, I tried several things, but nothing worked. It should call the method of the overwritten superclass.
Many thanks in advance for your help
Maybe you could do something like this:
for (name in protos) {
var super_function = ...; //wherever it comes from
protoObj[name] = protos[name];
protos[name]._super = super_function;
}
Then, from within the function, you should have access to the super function via this._super. You can even do this._super.call(this, ...) to ensure that the super function is called in the context of this.
Hopefully I'm understanding you correctly. Also, if I can make a suggestion, there might be an easier way to handle classical objects and inheritance. If you don't want to use Typescript, at least try the inheritance model that they use (which is quite common).
http://pastebin.com/Z2kaXqEv
EDIT: What helped me was using the Typescript playground (http://www.typescriptlang.org/Playground/). Play around with it and the class features it has, and see how it compiles to Javascript. That'll help you better understand exactly how you can accomplish classical inheritance in Javascript.
I tried this for XXXXXXXXXXXX, and it worked:
(function(name1, Base1){
return function() {
Base1.prototype[name1].apply(this, arguments);
};
})(name, Base);
I debugged a "jstring_super_init" function call in Firefox 19, Firebug 1.11.2.
Firebug behaved very strangely, jumping to wrong places of the code!!
Then, I inserted "console.log(this.cid);" after the superinit-call.
The cid, which is placed on to "this" in the init method of the super class, was there!!
When debugging with Google Chrome Version 25, it jumps to the right function!

getting the name of a variable through an anonymous function

Is it possible to find the name of an anonymous function?
e.g. trying to find a way to alert either anonyFu or findMe in this code http://jsfiddle.net/L5F5N/1/
function namedFu(){
alert(arguments.callee);
alert(arguments.callee.name);
alert(arguments.callee.caller);
alert(arguments.caller);
alert(arguments.name);
}
var anonyFu = function() {
alert(arguments.callee);
alert(arguments.callee.name);
alert(arguments.callee.caller);
alert(arguments.caller);
alert(arguments.name);
}
var findMe= function(){
namedFu();
anonyFu();
}
findMe();
This is for some internal testing, so it doesn't need to be cross-browser. In fact, I'd be happy even if I had to install a plugin.
You can identify any property of a function from inside it, programmatically, even an unnamed anonymous function, by using arguments.callee. So you can identify the function with this simple trick:
Whenever you're making a function, assign it some property that you can use to identify it later.
For example, always make a property called id:
var fubar = function() {
this.id = "fubar";
//the stuff the function normally does, here
console.log(arguments.callee.id);
}
arguments.callee is the function, itself, so any property of that function can be accessed like id above, even one you assign yourself.
Callee is officially deprecated, but still works in almost all browsers, and there are certain circumstances in which there is still no substitute. You just can't use it in "strict mode".
You can alternatively, of course, name the anonymous function, like:
var fubar = function foobar() {
//the stuff the function normally does, here
console.log(arguments.callee.name);
}
But that's less elegant, obviously, since you can't (in this case) name it fubar in both spots; I had to make the actual name foobar.
If all of your functions have comments describing them, you can even grab that, like this:
var fubar = function() {
/*
fubar is effed up beyond all recognition
this returns some value or other that is described here
*/
//the stuff the function normally does, here
console.log(arguments.callee.toString().substr(0, 128);
}
Note that you can also use argument.callee.caller to access the function that called the current function. This lets you access the name (or properties, like id or the comment in the text) of the function from outside of it.
The reason you would do this is that you want to find out what called the function in question. This is a likely reason for you to be wanting to find this info programmatically, in the first place.
So if one of the fubar() examples above called this following function:
var kludge = function() {
console.log(arguments.callee.caller.id); // return "fubar" with the first version above
console.log(arguments.callee.caller.name); // return "foobar" in the second version above
console.log(arguments.callee.caller.toString().substr(0, 128);
/* that last one would return the first 128 characters in the third example,
which would happen to include the name in the comment.
Obviously, this is to be used only in a desperate case,
as it doesn't give you a concise value you can count on using)
*/
}
Doubt it's possible the way you've got it. For starters, if you added a line
var referenceFu = anonyFu;
which of those names would you expect to be able to log? They're both just references.
However – assuming you have the ability to change the code – this is valid javascript:
var anonyFu = function notActuallyAnonymous() {
console.log(arguments.callee.name);
}
which would log "notActuallyAnonymous". So you could just add names to all the anonymous functions you're interested in checking, without breaking your code.
Not sure that's helpful, but it's all I got.
I will add that if you know in which object that function is then you can add code - to that object or generally to objects prototype - that will get a key name basing on value.
Object.prototype.getKeyByValue = function( value ) {
for( var prop in this ) {
if( this.hasOwnProperty( prop ) ) {
if( this[ prop ] === value )
return prop;
}
}
}
And then you can use
THAT.getKeyByValue(arguments.callee.caller);
Used this approach once for debugging with performance testing involved in project where most of functions are in one object.
Didn't want to name all functions nor double names in code by any other mean, needed to calculate time of each function running - so did this plus pushing times on stack on function start and popping on end.
Why? To add very little code to each function and same for each of them to make measurements and calls list on console. It's temporary ofc.
THAT._TT = [];
THAT._TS = function () {
THAT._TT.push(performance.now());
}
THAT._TE = function () {
var tt = performance.now() - THAT._TT.pop();
var txt = THAT.getKeyByValue(arguments.callee.caller);
console.log('['+tt+'] -> '+txt);
};
THAT.some_function = function (x,y,z) {
THAT._TS();
// ... normal function job
THAT._TE();
}
THAT.some_other_function = function (a,b,c) {
THAT._TS();
// ... normal function job
THAT._TE();
}
Not very useful but maybe it will help someone with similar problem in similar circumstances.
arguments.callee it's deprecated, as MDN states:
You should avoid using arguments.callee() and just give every function
(expression) a name.
In other words:
[1,2,3].forEach(function foo() {
// you can call `foo` here for recursion
})
If what you want is to have a name for an anonymous function assigned to a variable, let's say you're debugging your code and you want to track the name of this function, then you can just name it twice, this is a common pattern:
var foo = function foo() { ... }
Except the evaling case specified in the MDN docs, I can't think of any other case where you'd want to use arguments.callee.
No. By definition, an anonymous function has no name. Yet, if you wanted to ask for function expressions: Yes, you can name them.
And no, it is not possible to get the name of a variable (which references the function) during runtime.

Does Javascript have get/set keywords like C#?

I'm working with XULRunner and came across the following pattern in a code sample:
var StrangeSample = {
backingStore : "",
get foo() { return this.backingStore + " "; },
set foo(val) { this.backingStore = val; },
func: function(someParam) { return this.foo + someParam; }
};
StrangeSample.foo = "rabbit";
alert(StrangeSample.func("bear"));
This results in "rabbit bear" being alerted.
I've never seen this get/set pattern used in Javascript before. It works, but I can't find any documentation/reference for it. Is this something peculiar to XUL, a recent language feature, or just something I missed? I'm puzzled because I was specifically looking for something like this a few months ago and couldn't find anything.
For reference, removing "get" or "set" results in a syntax error. Renaming them to anything else is a syntax error. They really do seem to be keywords.
Can anyone shed some light on this for me, or point me towards a reference?
As suggested by Martinho, here are some links explaining the getter/setters in JS 1.5:
http://ejohn.org/blog/javascript-getters-and-setters/
http://ajaxian.com/archives/getters-and-setters-in-javascript
Be aware though, they don't seem to be supported in IE, and some developers have (legitimate) concerns about the idea of variable assignment having side-effects.
get/set are not reserved keywords as Daniel points out. I had no problem creating a top-level functions called "get" and "set" and using the alongside the code-sample posted above. So I assume that the parser is smart enough to allow this. In fact, even the following seems to be legitimate (if confusing):
var Sample = {
bs : "",
get get() { return this.bs; },
set get(val) { this.bs = val; }
}
According to Mozilla, they are not in ECMAScript.
JavaScript Setters And Getters:
Usually the setter and getter methods follow the following syntax in JavaScript objects. An object is created with multiple properties. The setter method has one argument, while the getter method has no arguments. Both are functions.
For a given property that is already created within the object, the set method is typically an if/else statement that validates the input for any time that property is directly accessed and assigned later on via code, a.k.a. "set". This is often done by using an if (typeof [arg] === 'certain type of value, such as: number, string, or boolean') statement, then the code block usually assigns the this.(specific)property-name to the argument. (Occasionally with a message logging to the console.) But it doesn't need to return anything; it simply is setting the this.specific-property to evaluate to the argument. The else statement, however, almost always has a (error) message log to the console that prompts the user to enter a different value for the property's key-value that meets the if condition.
The getter method is the opposite, basically. It sets up a function, without any arguments, to "get", i.e. return a(nother) value/property when you call the specific-property that you just set. It "gets" you something different than what you would normally get in response to calling that object property.
The value of setters and getters can be easily seen for property key-values that you don't want to be able to be directly modified, unless certain conditions are met. For properties of this type, use the underscore to proceed the property name, and use a getter to allow you to be able to call the property without the underscore. Then use a setter to define the conditions by which the property's key-value can be accessed and assigned, a.k.a. "set". For example, I will include two basic setters and getters for this object's properties. Note: I use a constant variable because objects remain mutable (after creation).
const person = {
_name: 'Sean';
_age: 27;
set age(ageIn) {
if (typeof ageIn === 'number') {
this._age = ageIn;
}
else {
console.log(`${ageIn} is invalid for the age's key-value. Change ${ageIn} to/into a Number.`);
return 'Invalid Input.';
}
},
get age() {
return this._age;
},
set name(nameIn) {
if (typeof nameIn === 'string') {
this._name = nameIn;
} else {
console.log(`Change ${nameIn} to/into a(ny) String for the name's
key-value.`);
return 'Invalid Input.';
}
},
get name() {
return this._name;
}
};
Where it gets interesting is when you try to set/assign a new key-value for the _age property, because it has to meet the if conditional in order to be successfully assigned, meaning not all assignments are valid, etc.
person.age = 'twenty-eight'; /* output: twenty-eight is invalid for the
age's key-value. Change twenty-eight to/into a Number. */
console.log(person.age); // output: 27 (twenty-eight was never assigned)
person.age = 28; // output: none
console.log(person.age); // output: 28
Note how I was able to access the person._age property via the person.age property thanks to the getter method. Also, similar to how input for age was restricted to numbers, input for the name property is now restricted/set to strings only.
Hope this helps clear things up!
Additionally, some links for more:
https://johnresig.com/blog/javascript-getters-and-setters/
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get
https://www.infragistics.com/community/blogs/infragistics/archive/2017/09/19/easy-javascript-part-8-what-are-getters-and-setters.aspx

Categories