Sometimes I find myself needing to initialize an object with a property that matches the property of another object. When the property name is the same, I want to be able to use shorthand syntax.
(For the purposes of the examples in this question, I'll just keep the additional properties to a tag: 1 property, and I'll reuse message in subsequent examples as the input/source of the information. I also indicate an extra unwanted property of message because I'm cherry-picking properties and do not intend to just use Object.assign to assign all the properties of message to the result.)
const message = {
person: {
name: 'John'
},
unwanted: 'x'
};
let result = { person: message.person, tag: 1 }; // Looking for shorthand for this
To formulate the result object above, I needed to type person twice. I was thinking there must be a shorthand way to do this. My reasoning for expecting this to work is that features exist like ES2015 Shorthand property names and Destructuring assignment. e.g:
const { person } = message; // destructing assignment
let result = { person, tag: 1 }; // shorthand property name for `person`
This would create an extra variable called person that has the value of message.person, And the result would have a property called person that has the desired value. But if there's no variable already existing then I don't know how to use shorthand in this case. And I haven't found a way to apply these two syntactical features together.
This was my first intuitive guess at what the syntax would be:
// hoping destructuring assignment is allowed in object literal
let result = { {person} = message, tag: 1 }; // it is not legal :(
My second guess was this:
// hoping that a property name would magically be inferred from `person`
let result = { message.person, tag: 1 }; // it is not legal :(
As a last resort I tried Object.assign, but it copies unwanted properties and does not cherry-pick just the person property of message.
let result = Object.assign({ tag: 1 }, message); // Assigns unwanted properties :(
So the best I have so far is { person: message.person, tag: 1 }
Is there shorthand initializer syntax to achieve this?
The best I have so far is { person: message.person, tag: 1 }.
Is there shorthand initializer syntax to achieve this?
No, this is still they way to go.
hoping that a property name would magically be inferred from person
let result = { message.person, tag: 1 };
There is the ECMAScript Shorthand Property Assignment Improvements proposal that would allow exactly this. Unfortunately, it's still at stage 0 :-/
Assuming you're using ES6:
const message = {
person: {
name: 'John'
},
unwanted: 'x'
};
let { unwanted, ...result } = { ...message, tag: 1 };
console.log(result);
If you'd like to rename the unwanted variable to something then to dit
let { unwanted: dummy, ...result } = { ...message, tag: 1 };
These have some issues, e.g
This creates an extra variable unwanted (or dummy if you use the 2nd approach)
If you have multiple unwanted properties, you have to write them all in the destructuring
So in my opinion, you're better off to go with the way you described in your question already.
Related
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
Learning from Codecademy. I have to get property of an object to a variable( not property value). This is messing with my brain from an hour.
Here is the code (I messed up a bit to find solution. Please use comments understand it correctly. I am confused to ask)
SCREENSHOT: http://prntscr.com/bcj94x
var james = {
job: "programmer",
married: false
};
// set to the first property name of "james"
var aProperty = james["job"];
// print the value of the first property of "james"
// using the variable "aProperty"
console.log(james["job"]);
console.log(aProperty);
I am getting: this in the console when run the script
programmer
programmer
Thanks
What result did you expect?
Defining your object using with the Javascript Object Notation (JSON for short) results in an object with two properties job and married.
This object is referenced via the variable james. Everytime you are using james in your code, you are dealing with the referenced object.
The same goes for var aProperty = james["job"];. Everytime, when your variable aProperty is used, it refers to the job property of the object referenced with james.
It is like saying: »From now on, when I say "aProperty", I mean the job-property of james«.
Your comment is a bit misleading:
// set to the first property name of "james"
In this case job is the first property. Correct would be set to the property named job.
From the above should the result be not unexpected.
console.log(james["job"]);
console.log(aProperty);
Both print programmer because aProperty is equivalent to james["job"] like saying Thomas or the person who wrote this is referencing to me and thus equivalent.
If you want to get the key associated to a given value, you can do this:
var james = {
job: "programmer",
married: false
};
Object.prototype.getKey = function (value){
for(var property in this){
if(this.hasOwnProperty(property)) {
if(this[property] === value )
return property;
}
}
};
console.log(james.getKey('programmer'));
It will give you "job".
So, using this function, you can simply write:
var aProperty = james.getKey('programmer');
You can use a for in loop to put the key values of the key : value pairs found in your james object inside an array called aProperty, and then print out your results in the console.
var james = {
job: "programmer",
married: false
};
var aProperty = [];
for (myvar in obj) {
if (obj.hasOwnProperty(myvar)) {
aProperty.push(myvar);
}
}
console.log(aProperty[0]);
console.log(aProperty[1]);
Why does Javascript syntax not support inline object literals with a variable property? For example:
const f = function (arg) {
console.log(arg);
}
f({}['some key'] = 1) // 1
f({ 'some key' : 1}) // [object Object] { some key: 1 }
Is there another alternative other than the two steps?
var o = {}
o['some key'] = 1
f(o)
Thanks!
Why does Javascript syntax not support inline object literals with a variable property?
You seem to be asking about variable properties, yet your examples do not use variables. Specifically, this example will work just fine.
f({ 'some key' : 1})
However, if you actually did want to use a variable without first creating the object, ECMAScript 6 now allows this.
So if this is your variable:
var my_variable = 'some key';
You can now use square brackets around the property name in the object literal, and it will use the value of the expression you provide:
var o = {[my_variable]: 1};
The o object will have a property named "some key". This only works in the implementations that support this syntax of course.
I am trying to run some JavaScript, but it is not working.
I have an object with two properties that are also objects.
var people = {
me: {
name: "Hello"
},
molly: {
name: "Molly"
}
};
And I am trying to make a function that uses a for/in statement and an if statement to list the properties of people.
var search = function (x) {
for (var a in people) {
if (people.a.name === x) {
return people.a;
}
}
};
So the function loops through the properties of people and assigns them to the variable a. Therefore people.a will be equal to a property of people. Then the function returns the property (people.a).
So if I type in me as parameter x, will the function should return the properties for the me object? I put this code in jsLint and jsHint and it passed, but I decided to remove the corrections because they were useless.
I then want to print the object properties in the browser:
var print = search("me");
document.getElementById("p").innerHTML(print);
I have this linked to an html document, with a tag id "p". I have tested javascript in the html document already, so I know that the javascript document is linked properly.
But the code will not work. Does anyone have any suggestions?
I have it working now thanks to the answers. But I thought that it would only print "Hello" to the screen, not { name: "Hello"}.
You need to use people[a], not people.a. The former looks for a property with the name of the value stored in a; the latter looks for a property literally named "a", which of course doesn't exist.
for (var a in people) {
if (people[a].name === x) {
return people[a];
}
}
Fiddle here.
Also, I think you meant search("Hello"), right? If not, then it would just be var search = function(x) { return people[x]; }.
people.a.name
you need to use the bracket operator if you want to access an item by name. Using people.a is literally searching for a member named 'a' instead of a member with the same name as the value of a.
Try:
people[a].name
instead.
4 errors in your code:
replace people.a with people[a]
replace innerHTML() with innerHTML
set HTML like this: document.getElementById("p").innerHTML = print.name;
As in a previous answer, search by name
Code: http://jsfiddle.net/nabil_kadimi/vVSPG/
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