Defining getters and setters after the object is instantiated - javascript

This bit of code comes from MDN:
var o = {
a: 7,
get b() {
return this.a + 1;
},
set c(x) {
this.a = x / 2
}
};
$('body').append(o.a + '<br>')
$('body').append(o.b + '<br>')
o.c = 50;
$('body').append(o.a + '<br>')
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
What I would like to do is break it down even further. I've gotten as far as line 3 like so:
var o = {}
o.a = 7
o.get b() { // broken
Is there a way that I can break the getters and setters out so that it's not one long definition inside the o = {}?

Object.defineProperty is what you're looking for:
var o = {};
Object.defineProperty(o, 'a', {
get: function() { return 1; },
set: function(val) { console.log(val) }
});

You can achieve this using Object.defineProperty():
Object.defineProperty(o, "b", {
get: function() {
// return something
}
})
See demo below:
var o = {};
o.a = 1;
Object.defineProperty(o, "b", {
get: function() {
return this.a + 1;
}
});
console.log(o.b)

Related

Setting properties on functions in JavaScript object literal notation

var api = {};
api.c = function () {return 1};
api.c.m = function () {return 2};
alert(api.c()); // returns 1
alert(api.c.m()); // returns 2
var api2 = {
c: function () {}; // can't put m inside c in object literal notation
};
How would we embed m in c in object literal notation?
You can't. However, you could do
Object.defineProperty(api.c, 'm', { value: function() { return 2; } });
Since Object.defineProperty returns the object, you could do
var api = {
c: Object.defineProperty(function() { }, 'm', {
value: function() { return 2; }
})
};
Or for multiple properties:
var api = {
c: Object.defineProperties(function() { }, {
m: { value: function() { return 2; } },
...
})
};
This may come closest to satisfying your desire to write the function properties in object literal form.
Or, you could use the extend feature available in most frameworks (or Object.assign in ES6):
var api = {
c: Object.assign(function() { }, {
m: function() { return 2; }
)
};
Feel free to replace Object.assign with $.extend, _.extend, etc.
Depending on your tolerance for ugliness, you might try the following, a variation on #zerkms's proposal without the IIFE (you'll need a variable x):
var api = {
c: (x = function() { }, x.m = function() { return 2; }, x)
};
It technically is possible, but it's ugly
var api2 = {
c: (function() {
var f = function() {};
f.m = 'something else';
return f;
}())
};
So I personally don't see a good reason to do it that way instead of how you do it in the 1st case.

Javascript object in an other object

I searching for an hour now (w/o any success), that how can I define an object in an other object (in javascript):
function UserStat(arr) {
var arrx = arr;
this.day = function(dateofday) {
//Some code going here which results will be stored variables like:
this.a = someInnerFunction();
this.b = someOtherFunction();
}
}
I'd like to access these variable when I create an instance of the outer function, somehow like this if this is possible:
var value = new UserStat(arr1).day('2012-10-20').a
Thank you in advance for any help!
I'm not sure how you wanted to use the dateofday variable, but this would work:
function UserStat(arr) {
var arrx = arr;
this.day = {
a: someInnerFunction,
b: someOtherFunction
};
}
new UserStat().day.a();
So would this:
function UserStat(arr) {
var arrx = arr;
this.day = (function(date){
var obj = {};
obj.a = someInnerFunction;
obj.b = someOtherFunction;
return obj;
}(dateofday));
}
Or even this:
function UserStat(arr) {
var arrx = arr;
this.day = new function() {
this.a = someInnerFunction,
this.b = someOtherFunction
};
}
function UserStat(arr) {
var arrx = arr;
this.day = function(dateofday) {
//Some code going here which results will be stored variables like:
var dayFunc = {
a: someInnerFunction,
b: otherFunc
}
return dayFunc;
}
}
​

Is it possible to /manipulate/ functions as it is strings?

var myString = '';
myString += 'foo';
myString += 'bar';
myString = myString.replace(/oba/, 'qux');
console.log(myString) // produces "foquxr"
Is there any way to likewise tinker around with functions, like, say, turning function(a) { a += 'b'; return a; } info function(a) { a += 'b'; console.log(a); return a + 'c'; }?
You can compose functions thus
// (compose(f, g))(x, y, ...) is the same as f(g(x, y, ...))
function compose(f, g) {
return function (var_args) {
return f.call(this, g.apply(this, arguments));
};
}
so
var f = compose(
function (x) { console.log(x); return x + 'c'; },
function (a) { a += 'b'; return a; });
lets you combine two small functions to get a function that behaves like
function(a) { a += 'b'; console.log(a); return a + 'c'; }
You could achieve this (without using eval) by getting the function's body from its declaration, manipulating it as needed, and redefining it by means of the Function() constructor:
function myFunction(a) { a += 'b'; return a; }
function changeFunction(){
var func = window['myFunction'].toString();
var body = func.substring(func.indexOf("{")+1, func.lastIndexOf("}"));
body = body.replace("return a;", "console.log(a); return a + 'c';");
window.myFunction = Function("a", body);
}​
Here's a JSFiddle

How to Extend javascript object methods

I have this object
var X = {
a:function(args){
},
b:function(args){
},
c: ...... etc
}
X.a() // will do somthing
I want to modify the method that it will do one more statement say "counter++"
So
var oldX = X.a();
X.a =function(args){
oldX(args);
counter++;
}
if i want to make this change to all the methods of the object X . So how can i do this by looping through the object like?
for(var i in X){
}
when i tried it by storing in an ooldArray of methods but while executing it will replace all the method with lastone ..
I'm completely sure the behavior you want should be achieved using prototypical inheritance. But I'm know nothing about your architecture and requirements, so here is the solution written in the way you want:
var x = {
a: function(){
console.log('x.a')
},
b: function(){
console.log('x.b')
}
},
oldx = {},
key;
for (key in x) {
oldx[key] = x[key];
(function(key){
x[key] = function(){
oldx[key].apply(this, arguments);
console.log('x.new_'+key);
}
})(key);
}
x.a();
x.b();
Here is what you want:
var x = {
a:function(){
return "this is a";
},
b:function(){
return "this is b";
},
c:function(){
return "this is c";
}
}
for(var abc in x)
{
alert(abc);
}

'this' context during object creation

I am trying to do something like this:
var test = {
a: 10,
b: 20,
c: (this.a+this.b)
};
but it doesn't work. How can I access the test.a from within test.c?
Is it possible?
It's not possible to reference "this" in an expression specifying an object literal. Either do it in a following line or use a constructor like this:
function myobj(a,b) {
this.a = a;
this.b = b;
this.c = this.a + this.b;
}
var test = new myobj(10,20);
In response to which method is faster, creation with the object constructor is faster. Here's a simple test case comparison. Run it yourself on JSBIN.
The results show that the object creation with a constructor vs an object literal is almost twice as fast:
0.450s : testObjectLiteral
0.506s : testObjectLiteralWithFunction
0.280s : testConstructor
Here's the test code inlined as well:
// timer function
function time(scope){
time.scope = time.scope || {};
if(time.scope[scope]) {
var duration = (new Date()).getTime()-time.scope[scope];
time.scope[scope] = null;
var results = document.getElementById("results");
results.innerHTML = results.innerHTML + '<p>'+(duration/1000).toFixed(3)+'s : '+scope+'</p>';
} else {
time.scope[scope] = (new Date()).getTime();
}
}
// object creation function with constructor
function myobj(a,b) {
this.a = a;
this.b = b;
this.c = this.a + this.b;
}
function testConstructor(iterations) {
var objs = new Array(iterations);
for(i=0;i<iterations;i++) {
objs[i] = new myobj(i,i+1);
}
return objs;
}
function testObjectLiteralWithFunction(iterations) {
var objs = new Array(iterations);
for(i=0;i<iterations;i++) {
objs[i] = {
a: i,
b: i+1,
c: function() {
return this.a + this.b;
}
};
}
return objs;
}
function testObjectLiteral(iterations) {
var objs = new Array(iterations);
for(i=0;i<iterations;i++) {
var item = {
a: i,
b: i+1
};
item.c = item.a + item.b;
objs[i] = item;
}
return objs;
}
var ITERATIONS = 1000000;
time("testObjectLiteral");
testObjectLiteral(ITERATIONS);
time("testObjectLiteral");
time("testObjectLiteralWithFunction");
testObjectLiteralWithFunction(ITERATIONS);
time("testObjectLiteralWithFunction");
time("testConstructor");
testConstructor(ITERATIONS);
time("testConstructor");
​
It's not possible within an object literal since this cannot be made to refer to an object that has not yet been created. Your best option is to assign the c property in a separate step:
var test = {
a: 10,
b: 20
};
test.c = test.a + test.b;
You simply can't do this when declaring an object literal, the closest you can do is:
var test = {
a: 10,
b: 20
};
test.c = test.a + test.b;
In your context this refers to whatever parent context you're in, not the test object...and even if it did, you can't declare members like that, for example this is also invalid:
var test = { a: 10, b: 20, test.c: test.a + test.b };
...because test, a and b aren't defined yet, since it's a single statement that hasn't completed.
Why not make c a function so that it always returns the current value of a+b?
var test = {
a: 5,
b: 1,
c: function() {
return this.a + this.b;
}
}

Categories

Resources