Assign function stored in variable as getter in object literal - javascript

Say I have a function. If I wanted to add it as a method to an object, I would use:
let foofunc = function() {}
{
foo: foofunc
}
However, what if I want to add it as a getter? You'd think I could do it like this:
{
get x: foofunc
}
but my IDE complains, so I assume that's not possible. How would I do this?

You can use the Object.defineProperty function like so:
function getterFunc() { return 1; }
let anObject = {};
Object.defineProperty(anObject, 'propertyName', {get: getterFunc});
Live Example:
function getterFunc() { return 1; }
let anObject = {};
Object.defineProperty(anObject, 'propertyName', {get: getterFunc});
console.log(anObject.propertyName); // 1
You can access use the getter normally by doing anObject.propertyName.
The MDN page has more detailed information if you still have more questions.

To make it as getter function..
let foofunc = function() { return this.x;}
let obj = {
x: "marvel",
get foo(){return foofunc.call(this)}
};
use:
console.log(obj.foo);

Related

When is a getter function useful in JavaScript?

Specifically when used within objects, when would a getter function be used over a regular function. For example, what is the difference between using
const obj = {
get method() {
return data;
}
};
console.log(obj.method);
and this
conts obj = {
method() {
return data;
}
};
console.log(obj.method());
1 . With a normal property/method, you can change its value.
A getter method cannot have its value changed. Look what happens when we try to change the getter here (it doesn't change):
const obj = {
methodNormal() {
return 5;
},
get methodGetter() {
return 5;
}
};
obj.methodNormal = "red";
obj.methodGetter = "blue";
console.log(obj);
2 . Secondly, with a normal property you have the luxury of either returning the function i.e. obj.methodNormal or returning the function executing i.e. obj.methodNormal(). With getter functions you do not have the luxury of returning the function. You can only do obj.methodGetter which executes that function. The code snippet below demonstrates that.
const obj = {
methodNormal() {
return 5;
},
get methodGetter() {
return 5;
}
};
let captureNormalMethod = obj.methodNormal;
let captureGetterMethod = obj.methodGetter;
console.log(captureNormalMethod);
console.log(captureGetterMethod);
Both these qualities - being unchangeable & unable to be captured in a new variable or property - contribute to getter functions having a sense of 'hiddenness'. Now you can understand what people mean when they say getters are 'read-only' properties!
Further reading:
What I've been referring to as 'normal properties' are called data properties (good article).
Getter methods are an example of what are called accessor properties (good article).
A method can only return data a property can also have a setter
This is useful if you want to expose read-only properties. It isn't just a function to the caller.
In your example, both do the same thing, but the importance is not how they are alike but how they are not. You can, for example, pass the method version as an argument somewhere else to do some lazy execution, but the getter won't work like that.
const obj = {
lazyProp(parameter) {
return parameter + 2;
}
}
function evaluateLazy(fn) {
return fn()
}
evaluateLazy(obj.lazyProp)
One useful scenario is where you want to use regular property access on all your properties, but need to invoke a method to calculate a given value. For example take the following example which doesn't use a getter. It ends up printing the function, not the return value of the function. Without a getter, we would need to handle a specific case where the value is a function, and then invoke it.
const obj = {
x: 10,
y: 20,
total() {
return this.x + this.y;
}
}
const prettyPrintObj = obj => {
for(let key in obj) {
console.log(`${key.toUpperCase()} is ${obj[key]}`);
}
}
prettyPrintObj(obj);
However, with a getter, we can use the same function, and don't need to handle specific cases for where obj[key] is a function, as simply doing obj[key] on a getter will invoke the function for you:
const obj = {
x: 10,
y: 20,
get total() {
return this.x + this.y;
}
}
const prettyPrintObj = obj => {
for(let key in obj) {
console.log(`${key.toUpperCase()} is ${obj[key]}`);
}
}
prettyPrintObj(obj);

How can I get a property name inside the property itself in Javascript?

Is there a way I can get a property`s name inside the property itself?
I mean something like this:
let myObj = {
myProperty: {
name: <propertyName>.toString()
}
};
console.log(myObj.myProperty.name); // Prints `myProperty`
No, there isn't. There's nothing available when the object initializer is evaluated that provides that information.
Presumably if this were a one-off, you'd just repeat the name. If it's not a one-off, you could give yourself a utility function to do it:
// Define it once...
const addProp = (obj, name, value = {}) => {
obj[name] = value;
value.name = name;
return obj;
};
// Then using it...
let myObj = {};
addProp(myObj, "myProperty");
addProp(myObj, "myOtherProperty", {foo: "bar"});
console.log(myObj.myProperty.name);
console.log(myObj.myOtherProperty.name);

Getter/Setter as function

Is it possible to create property getter/setter as a function?
Standard getter/setter work like following:
class Test {
something: any;
get prop() {
return something;
}
set prop(value) {
something = value;
}
}
let instance = new Test();
instance.prop = 'Foo';
console.log(instance.prop); // = Foo
I would need following:
let instance = new Test();
instance.prop('Bar') = 'Foo'; // access setter as a function of prop
console.log(instance.prop('Bar')); // = Foo
Yes, I know it's unorthodox usage and yes, I know that I could implement this functionality bit differently. I'm just interested if this is possible in JS/TS/ES6.
Update
This is the closest I got:
class Test {
something: any;
prop(area /* my custom symbol type */) {
const obj: any = {};
Object.defineProperty(obj, 'value', {
// get child object of my complex object
get: () => this.something[area];
// replace part of my complex object
set: (value) => {
this.something = {...this.something, [area]: value}
}
});
}
}
let instance = new Test();
instance.prop('Bar').value = 'Foo';
console.log(instance.prop('Bar').value); // = Foo
So in short, I'd like to get rid of value suffix if possible.
As #deceze mentioned in the first comment, it is not possible to assign to function call, so solution in the update is as best as it gets.

Creating a function with properties

Sorry, I donĀ“t know the name of this.
I want to have a function and an object with properties in only one variable.
Here is how it works:
var obj = function() {
return "foo";
};
obj.prop = "bar";
obj(); // => "foo"
obj.prop; // => "bar"
This works fine, but I would like to change the order of this:
var obj = { prop: "bar" };
obj = function() {
return "foo";
};
obj(); // => "foo"
obj.prop; // => undefined
Is there a way to do this?
I want do do this because I have a lot of properties to add to the object:
var obj = function() {
return "foo";
};
obj.prop1 = "bar1";
obj.prop2 = "bar2";
obj.prop3 = "bar3";
obj.prop4 = "bar4";
obj.prop5 = "bar5";
obj.prop6 = "bar6";
obj.prop7 = "bar7";
//...
This isn't possible because when you do:
obj = function() {
return "foo";
};
...you're assigning the variable obj to the new function, so it no longer points to the original object you created ({ prop: "bar" }) at all.
So if you want to add properties to a function object, you must always create the function first, then add properties.
As an alternative, you could do something like this:
var props = {
prop1: "bar1",
prop2: "bar2"
};
var obj = function() {
return "foo";
};
for (var key in props) {
obj[key] = props[key];
}
Or if you happen to have jQuery available (and don't have Object.assign available):
jQuery.extend(obj, props);
(Of course there are shims available for Object.assign, which would allow #Pointy's answer to work in older browsers.)
If you want to do this with one statement, ES2015 (and some libraries) let you do:
var obj = Object.assign(
function() { /* ... */ },
{ "hello": "world" }
);
Which will give you obj as a function with the property "hello". Note that this is really just the same thing as the separate assignment, but it's all wrapped up as one overall expression, which is nice because it means you can do something like
return Object.assign(function() { /* whatever */ }, {
prop: whatever,
// ...
});
I also agree with Grundy, but you could do something like that:
var x = function(){
var obj = {};
return {
objToReturn: obj,
objFunction: function(){return 'foo';},
addItemsToObject: function (key, value) {
obj[decodeURIComponent(key)] = value;
}
}
};
I honestly don't know if that's what you really want, but in that case you can execute the "x" function and after you can access the
"objFunction", the "objToReturn" or the "addItemsToObject" function.
So it will be something like that:
var y = x();
for (propertie in yourProperties){
y.addItemsToObject
(propertie, yourProperties[decodeURIComponent(propertie)]);
}
And then:
y.objFunction();
'foo'
Hope that helps.

Passing object as parameter to constructor function and copy its properties to the new object?

I have a JavaScript constructor like this:
function Box(obj) {
this.obj = obj;
}
which i want to pass an object as a parameter like this:
var box = new Box({prop1: "a", prop2: "b", prop3: "c"})
and gives me something like this:
box.obj.prop1
box.obj.prop2
box.obj.prop3
but I would like the properties to be directly on the object like this:
box.prop1
box.prop2
box.prop3
I know I could do something like this:
function Box(obj) {
this.prop1 = obj.prop1;
this.prop2 = obj.prop2;
this.prop3 = obj.prop3;
}
But that is not good because then my constructor would have to "know" before the names of the properties of the object parameter. What I would like is to be able to pass different objects as parameters and assign their properties directly as properties of the new custom object created by the constructor so I get box.propX and not box.obj.propX. Hope I am making myself clear, maybe I am measing something very obvious but I am a newbie so please need your help!
Thanks in advance.
You could do this. There is probably also a jquery way...
function Box(obj) {
for (var fld in obj) {
this[fld] = obj[fld];
}
}
You can include a test for hasOwnProperty if you've (I think foolishly) extended object
function Box(obj) {
for (var fld in obj) {
if (obj.hasOwnProperty(fld)) {
this[fld] = obj[fld];
}
}
}
Edit
Ah, ha! it's jQuery.extend
So, the jQuery way is:
function Box(obj) {
$.extend(this, obj);
}
Simply put this in your constructor
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
this[prop] = obj[prop];
}
}
Really short
function Box(obj) {
Object.assign(this, obj);
}
Here's an example with the javascript module pattern:
var s,
NewsWidget = {
settings: {
numArticles: 5,
articleList: $("#article-list"),
moreButton: $("#more-button")
},
init: function(options) {
this.settings = $.extend(this.settings, options);
s = this.settings;
this.bindUIActions();
},
bindUIActions: function() {
s.moreButton.on("click", function() {
NewsWidget.getMoreArticles(s.numArticles);
});
},
getMoreArticles: function(numToGet) {
// $.ajax or something
// using numToGet as param
}
};
$(function(){
NewsWidget.init({
numArticles: 6
});
console.log(s.numArticles);
});

Categories