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;
}
}
Related
I'm trying to allow transformation of a tree structure using a transform method that maps the nodes in the tree. The nodes in the tree are defined using get-type getters, and these don't get updated when I make a new copy and transform the node's contained value.
As an example, consider this simplified version:
function node() {
return {
foo: '123',
get blah() { return this.foo; },
transform(f) {
const copy = {};
Object.assign(copy, this);
copy.foo = f(copy.foo);
return copy;
}
};
}
const a = node();
const b = a.transform(value => '456');
a.blah
b.blah
The getter in the transformed copy continues to return '123' even after foo has been updated to '456'.
What would be the proper way of returning a transformed copy of the object but with the getters referencing the updated object rather than the source?
Object.assign will invoke getters; they will not exist anymore:
function node() {
return {
foo: '123',
get blah() { console.log('invoked');return this.foo; },
transform(f) {
const copy = {};
Object.assign(copy, this);
copy.foo = f(copy.foo);
return copy;
}
};
}
const a = node();
const b = a.transform(value => '456');
console.log(Object.getOwnPropertyDescriptor(b, 'blah'));
You can copy the descriptors instead with getOwnPropertyDescriptors, then assign them with Object.defineProperties:
function node() {
return {
foo: '123',
get blah() { return this.foo; },
transform(f) {
const copy = {};
const descriptors = Object.getOwnPropertyDescriptors(this);
Object.defineProperties(copy, descriptors);
copy.foo = f(copy.foo);
return copy;
}
};
}
const a = node();
const b = a.transform(value => '456');
console.log(a.blah);
console.log(b.blah);
I would start with the node function itself being used to return the copy, i.e. it can create fresh immutable objects with any foo value:
function node(foo) {
return {
foo,
get blah() { return this.foo; },
transform(f) {
return node(f(this.foo));
}
};
}
const a = node('123');
const b = a.transform(value => '456');
console.log(a.blah);
console.log(b.blah);
Personally, I would just use a constructor like:
function Node(){
let wow = 'will not change length'; // I like that
this.foo = '123';
Object.defineProperties(this, { //put all getters and setters in here
blah:{
get:()=>this.foo
},
length:{
get:()=>{
let l = 0;
for(let i in this)l++;
return l;
}
}
});
}
const a = new Node, b = new Node;
b.foo = '456'; a.newProp = 'test';
console.log(a.blah); console.log(a.length); console.log(b.blah); console.log(b.length);
but, you might want to use a class:
class Node{
constructor(){
this.foo = '123';
}
get blah(){
return this.foo;
}
get length(){
let l = 0;
for(let i in this)l++;
return l;
}
}
const a = new Node, b = new Node;
b.foo = '456'; a.newProp = 'test';
console.log(a.blah); console.log(a.length); console.log(b.blah); console.log(b.length);
I personally prefer constructors, since you can have private variables in all Browsers.
var modularpattern = (function () {
var sum = 0;
return {
add: function () {
sum = sum + 1;
return sum;
},
}
} ());
var c = modularpattern;
c.add(); // 1
var d = modularpattern;
d.add(); // 2 but I want to be 1
console.log(modularpattern.add()); // alerts: 3
Is it possible to have more objects not only one? I want to have private fields but at the same time also having more that just one object?
Yes, that's easily possible by dropping the IIFE invocation to get a normal function instead. Only it's called factory pattern then, no longer module.
function factory() {
var sum = 0;
return {
add: function () {
sum = sum + 1;
return sum;
}
}
}
var c = factory();
c.add(); // 1
var d = factory();
d.add(); // 1
console.log(c.add()); // logs: 2
You can use the module pattern to create a factory which uses the module pattern to create more objects. Using your original example, it would look something like this:
var moduleFactory = (function() {
return {
create: function() {
return (function() {
var sum = 0;
return {
add: function() {
sum = sum + 1;
return sum;
}
}
})();
}
}
}
)();
var c = moduleFactory.create();
console.log(c.add()); //1
var d = moduleFactory.create();
console.log(d.add()); //1
I am new to Javascript. I have defined an object using object initializer method.
var obj = { a : "A";
b : "B";
myFunc = function() {
alert("Hello"):
}
Now I want to create another object that will be child of Obj. How can I do that.
var obj1 = new obj();
is not working.
First off, you have a syntax error with
myFunc = function() { ...
Anyway, this is how you'll want to set it up
function Foo() {
this.a = "A";
this.b = "B";
}
Foo.prototype.myFunc = function() {
alert("hello");
};
Now to create your child object
function Bar() {
Foo.call(this); // call parent constructor; optional
}
// setup child prototype
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.constructor = Bar;
Check it out
var b = new Bar();
b instanceof Bar; // true
b instanceof Foo; // true
b.constructor.name; // Bar
b.myFunc; // "hello"
To do it the way you wanted to:
var obj = {
a: "A",
b: "B",
myFunc: function () {
alert("Hello");
}
};
var obj1 = Object.create(obj)
obj1.a = 2;
console.log(obj1);
console.log(obj);
Let's say I have a JavaScript object:
function a(){
var A = [];
this.length = function(){
return A.length;
};
this.add = function(x){
A.push(x);
};
this.remove = function(){
return A.pop();
};
};
I can use it like so:
var x = new a();
x.add(3);
x.add(4);
alert(x.length()); // 2
alert(x.remove()); // 4
alert(x.length()); // 1
I was trying to make .length not a function, so I could access it like this: x.length, but I've had no luck in getting this to work.
I tried this, but it outputs 0, because that's the length of A at the time:
function a(){
var A = [];
this.length = A.length;
//rest of the function...
};
I also tried this, and it also outputs 0:
function a(){
var A = [];
this.length = function(){
return A.length;
}();
//rest of the function...
};
How do I get x.length to output the correct length of the array inside in the object?
You could use the valueOf hack:
this.length = {
'valueOf': function (){
return A.length;
},
'toString': function (){
return A.length;
}
};
Now you can access the length as x.length. (Although, maybe it's just me, but to me, something about this method feels very roundabout, and it's easy enough to go with a sturdier solution and, for example, update the length property after every modification.)
If you want A to stay 'private', you need to update the public length property on every operation which modifies A's length so that you don't need a method which checks when asked. I would do so via 'private' method.
Code:
var a = function(){
var instance, A, updateLength;
instance = this;
A = [];
this.length = 0;
updateLength = function()
{
instance.length = A.length;
}
this.add = function(x){
A.push(x);
updateLength();
};
this.remove = function(){
var popped = A.pop();
updateLength();
return popped;
};
};
Demo:
http://jsfiddle.net/JAAulde/VT4bb/
Because when you call a.length, you're returning a function. In order to return the output you have to actually invoke the function, i.e.: a.length().
As an aside, if you don't want to have the length property be a function but the actual value, you will need to modify your object to return the property.
function a() {
var A = [];
this.length = 0;
this.add = function(x) {
A.push(x);
this.length = A.length;
};
this.remove = function() {
var removed = A.pop();
this.length = A.length;
return removed;
};
};
While what everyone has said is true about ES3, that length must be a function (otherwise it's value will remain static, unless you hack it to be otherwise), you can have what you want in ES5 (try this in chrome for example):
function a(){
var A = [],
newA = {
get length(){ return A.length;}
};
newA.add = function(x){
A.push(x);
};
newA.remove = function(){
return A.pop();
};
return newA;
}
var x = a();
x.add(3);
x.add(4);
alert(x.length); // 2
alert(x.remove()); // 4
alert(x.length); // 1
You should probably use Object.create instead of the function a, although I've left it as a function to look like your original.
I don't think you can access it as a variable as a variable to my knoledge cannot return the value of a method, unless you will hijack the array object and start hacking in an update of your variable when the push/pop methods are called (ugly!). In order to make your method version work I think you should do the following:
function a(){
this.A = [];
this.length = function(){
return this.A.length;
};
this.add = function(x){
this.A.push(x);
};
this.remove = function(){
return this.A.pop();
};
};
These days you can use defineProperty:
let x = {}
Object.defineProperty(x, 'length', {
get() {
return Object.keys(this).length
},
})
x.length // 0
x.foo = 'bar'
x.length // 1
Or in your specific case:
Object.defineProperty(x, 'length', {
get() {
return A.length
}
})
function a(){
this.A = [];
this.length = function(){
return this.A.length;
};
this.add = function(x){
this.A.push(x);
};
this.remove = function(){
return this.A.pop();
};
};
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;
}
}