'this' context during object creation - javascript

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;
}
}

Related

Experiment: Can a JavaScript instance be a constructor itself & have its own set of instances?

let bar;
function foo(){
this.x=x;
this.y=y;
}
bar=new foo(1,2);
/*Since all functions in javascript are objects.
Why can't an instance an object be a constructor itself?*/
!function bar(a,b){
this.a=a;
this.b=b;
}(); // (1)
let bar1=new bar(3,4);
console.log(bar1.a);
(1): Using a named IIFE, can bar be an instance and a constructor at the same time?
It's just a fun trick to exploit the language's freedom to see if it is a possibility, any other ways of doing this?
It sounds like you are looking for a constructor-function-returning function:
function makeBar(x, y) {
function Bar(a, b) {
this.a = a;
this.b = y + b;
}
Bar.x = x;
return Bar;
}
var Bar1 = makeBar("bar1", 2);
console.log(Bar1.x); // "bar1"
var myBar1 = new Bar1(1, 2); // Bar { a: 1, b: 4 }
console.log(myBar1 instanceof Bar1); // true
var Bar2 = makeBar("bar2", 0);
var myBar2 = new Bar2(3, 3); // Bar { a: 3, b: 3 }
console.log(myBar2 instanceof Bar1); // false
To make makeBar not a factory function but a constructor with a working prototype, you'd have to use
function Foo(x, y) {
function Bar(a, b) {
this.a = a;
this.b = y + b;
}
Object.setPrototypeOf(Bar, Foo.prototype);
Bar.x = x;
return Bar;
}
Foo.prototype.log = function() {
console.log("I'm "+this.name);
};
var Bar = new Foo("bar", 2);
Bar.log();
console.log(Bar instanceof Foo); // true
var myBar = new Bar(1, 2);
console.log(myBar instanceof Bar); // true
Can a JavaScript instance be a constructor itself & have its own set of instances?
Sure, a function is an instance of Function and a constructor is a function.
So you can just have
const instance1 = new Function("a", "this.a = a;");
const instance2 = new instance1("foo");
console.log(instance2.a); // "foo"
If you need instance1 to be more than a raw Function, you can even extend this constructor:
class MyFunc extends Function {
doSomethingMore(){ console.log("I'm doing more"); }
}
const instance1 = new MyFunc("a", "this.a = a;");
instance1.doSomethingMore();
const instance2 = new instance1("foo");
console.log(instance2.a); // "foo"
But I can't see a clear reason why you'd ever want to do that...
(Note that dynamically creating a function via the Function constructor is generally less "performant" than at parse time through function expression or statement.)
In your code, since bar is declared with let, it can't be re-declared as a function declaration in the same scope.
If you wanted to do this, you could have foo explicitly return a function, which could then be called with new:
function foo(x, y) {
this.x = x;
this.y = y;
return function bar(a, b) {
this.a = a;
this.b = b;
};
}
const bar = new foo(1, 2);
const bar1 = new bar(3, 4);
console.log(bar1.a);

How add methods from a class to a JSON object

I have a class defined in Javascript with some members and methods. I also have a JSON object that has the same member variables as my class but, obviously, not the methods. What is the easiest way to convert my JSON object to an instance of the class?
Below some code that explains better my case. I've tried to use Object.assign without success. Can this be done in a one liner?
function Thing(a, b){
this.a = a;
this.b = b;
this.sum = function(){ return this.a + this.b; };
this.printSum = function(){ console.log (this.sum()); };
};
// test it works
z = new Thing(4,3);
z.printSum(); // shows 7
// attempt with Object.assign
y = JSON.parse('{"a": 5, "b": 4}'); // initialize y from JSON object
console.log(y);
Object.assign(y, new Thing()); // trying to copy methods of Thing into y
console.log(y); // shows both a and b undefined (assign overwrited also a and b)
y.printSum(); // shows NaN
// trying Object.assing the other way around
y = JSON.parse('{"a": 5, "b": 4}');
Object.assign(new Thing(), y); // trying the other way around
console.log(y); // methods from thing are not present now
y.printSum(); // gives error y.printSum is not a function (obvious, as it is not present)
You rather need to change the sum function to make it return sum of this.a and this.b.
Also, instead of Object.assign, you need to change the prototype of the variable y so that the methods are available to it.
function Thing(a, b){
this.a = a;
this.b = b;
this.sum = function(){ return this.a + this.b; };
this.printSum = function(){ console.log (this.sum()); };
};
// test it works
z = new Thing(4,3);
z.printSum(); // shows 7
// attempt with Object.assign
y = JSON.parse('{"a": 5, "b": 4}'); // initialize y from JSON object
console.log(y);
y.__proto__ = new Thing(); // trying to copy methods of Thing into y
console.log(y); // shows both a and b undefined (assign overwrited also a and b)
y.printSum();
Do you mind to make some changes? Lets change Thing input params to Object. And then you can easily pass parsed json into it.
Is it suitable for you?
function Thing(obj) {
this.a = obj.a;
this.b = obj.b;
this.sum = function(){ return this.a + this.b; };
this.printSum = function(){ console.log (this.sum()); };
};
y = JSON.parse('{"a": 5, "b": 4}');
t = new Thing(y);
t.printSum();
It possible to add object as optinal param:
function Thing(a, b, obj = null) {
if (!obj) {
this.a = a;
this.b = b;
} else {
this.a = obj.a;
this.b = obj.b;
}
this.sum = function(){ return this.a + this.b; };
this.printSum = function(){ console.log (this.sum()); };
};
y = JSON.parse('{"a": 5, "b": 4}');
t = new Thing(null, null, y);
t.printSum();
tt = new Thing(5, 4);
t.printSum();

Defining getters and setters after the object is instantiated

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)

Inheritance from Object initializer in javascript

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);

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;
}
}
​

Categories

Resources