Use object values as new values inside same object [duplicate] - javascript

This question already has answers here:
Self-references in object literals / initializers
(30 answers)
Closed 8 years ago.
I am trying to do something like this:
var obj = {
a: 5,
b: this.a + 1
}
(instead of 5 there is a function which I don't want to execute twice that returns a number)
I can rewrite it to assign obj.b later from obj.a, but can I do it right away during declaration?

No. this in JavaScript does not work like you think it does. this in this case refers to the global object.
There are only 3 cases in which the value this gets set:
The Function Case
foo();
Here this will refer to the global object.
The Method Case
test.foo();
In this example this will refer to test.
The Constructor Case
new foo();
A function call that's preceded by the new keyword acts as a constructor. Inside the function this will refer to a newly
created Object.
Everywhere else, this refers to the global object.

There are several ways to accomplish this; this is what I would use:
function Obj() {
this.a = 5;
this.b = this.a + 1;
// return this; // commented out because this happens automatically
}
var o = new Obj();
o.b; // === 6

This should return the correct values:
function () {
var aVar = 5;
var bVar = aVar + 1;
return {
a : aVar,
b : bVar;
}
}();

As it turns out you can't reference an object inside another object unless the first one is a function. But you can do it this way.
var obj = {
a: 5
}
obj.b = obj.a + 1; // create field b in runtime and assign it's value
If you console.log(obj) you will have
obj = {
a: 5,
b: 6
}
This way you keep the object literal structure for the remaining part of the code

No, in your example, the value of this doesn't refer to the object literal.
You'll need to assign a value to b after the object has been created in order to base it on another property in obj.

in chrome debugger
> var o = {a: 5, b: this.a+1}
undefined
> o.b
NaN
> o.a
5

No. this will take the same meaning as it would outside the definition.

Related

How is this variable scope resolving performed exactly? [duplicate]

This question already has answers here:
variable binding inside an object
(2 answers)
Closed 2 years ago.
While trying to understand how javaScript resolve variable, i wrote this code:
const a = 0;
var obj = {a: 1, foo: function(){console.log(a);}};
obj.foo();
I know that javaScript, like most of the programming languages, use the lexical/static scope to resolving variables.
But in this example, the lexical scope outside of foo function is obj scope and not global scope.
So why do i get output 0 instead of 1 ?
the lexical scope outside of foo function is obj scope and not global scope.
There is no such thing as "obj scope" or "object scope". In Javascript, every variable name (or identifier) is scoped to either a block (such as inside a loop, or inside a function block), or is global.
An object isn't a block. Putting a property on an object does not create a new identifier; referencing such a property name as if it were a standalone variable does not work, because it's not an identifier in scope.
The only time in which something like this would be possible would be if you used with and referenced the property as if it was a standalone variable inside the with block, but with should never be used.
const a = 0;
var obj = {
a: 1,
foo: function() {
console.log(a);
}
};
with (obj) {
console.log(a);
}
In an object with {a: 1} the 'a' is a string, not a variable. It does not assign 1 to 'a'. Instead it sets a key/value pair equivalent to { "a": 1 }.
It has nothing to do with scope. The variable a defined in the first line is the only variable of that name and never has its value changed in the code you gave.
Note also that you defined it as const meaning it cannot be assigned a different value.
If you need reference the a object property, is necessary use this.a, because a without this is the global variable.
const a = 0;
var obj = {a: 1, foo: function(){console.log(this.a);}};
obj.foo();
Because there is only one a, and it's declared on your first line.
In order to use this object's variables, you have to use this. For example:
const a = 0
var obj = { a: 1, foo: function() { console.log(this.a) } }
obj.foo(); // 1
When you use this.a, that's the same thing, if you use obj.a outside of this object.
To understand this better, you can check the example below:
const mark = 10
const obj = {
name: 'Sardor',
mark: mark,
setMark: function(num) { this.mark = num },
getMark: function() { console.log(this.mark) }
}
obj.getMark() // 10
obj.setMark(8)
obj.getMark() // 8
console.log(mark) // 10
It means, that you filled mark by the date of num. Then you called .setMark() function of obj and changed its value to 8. But you didn't change the variable mark, that is outside of obj. That's why finnaly you have 8 in obj.mark and 10 in mark.
Advice: read more about this

Why object const can be changed after definition in JavaScript? [duplicate]

This question already has answers here:
Why can I change a constant object in javascript
(12 answers)
Closed 9 months ago.
In JavaScript:
const a = 6;
a = 2; // Error
const o = {};
o = 7; // Error
o.a = 5; // Good. Why?
const o = {a:1};
o.a = 2; // Good. Why?
I found people sometimes define a const object but later change its value. Why a const can be changed after its definition?
A variable declared with const means one thing: the standalone variable name cannot be reassigned with = later.
In contrast, o.a = 5; is not reassigning the variable name - it's mutating the content of the object, but it's not changing what the o variable points to in memory.
To prevent reassignment of a variable name, use const. To prevent mutation of an object is something entirely different - for that, you'd need something like Object.freeze or manipulate objects using immutable-js.
In the first case, a is const and cannot be reassigned. In the second and third, the object o is const so that object cannot be assigned another value, but its properties are not const. See here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
The const declaration creates a read-only reference to a value. It does not mean the value it holds is immutable, just that the variable identifier cannot be reassigned. For instance, in the case where the content is an object, this means the object's contents (e.g., its properties) can be altered.
const variables aren't enforced to be immutable.
From MDN:
Constants are block-scoped, much like variables defined using the let statement. The value of a constant can't be changed through reassignment, and it can't be redeclared.
Emphasis mine.
o.a = 5 isn't reassigning o; it's reassigning a property in o.
For adding more information from the other answers, if you want to define a constant object property. You can try these ways:
const o = {
get a() {
return 1;
}
};
o.a = 2;
// 1
console.log(o.a);
const o2 = {};
Object.defineProperty(o2, 'a', {
value: 1,
writable: false,
enumerable: true,
configurable: true
});
o2.a = 2;
// 1
console.log(o2.a);

using key value pair of same object inside itself with 'this' in javascript

Let's say I have two objects like
var a = {
b: 1,
c: this.b
};
And
var funcObj = {
b : function() {
return 1;
},
c: function() {
console.log(return this.b())
}
}
On logging these two like
console.log(a.c)//results undefined
console.log(funcObj.c()) //results 1
Why can't the first function use the this property but the second one can?
I am really confused.
The answer depends on what this refers to in each context. In JavaScript, this is bound to whatever object was on the left of the dot (.) when the current function was called. If we're not in a function, things get a little hairier -- this is either the global window object or undefined, depending on the environment.
In your first example, the value of this is dependent on the surrounding context. As JavaScript builds your object a, it evaluates this.b. Whatever object this is currently bound to has no b property, so the c property is set to undefined.
In your second example, when you call funcObj.c() the this in the function gets bound to funcObj. So, when you ask for the b property, you get the b you defined above. The fact that funcObj.b is a function is actually irrelevant. The following would work just as well:
var funcObj = {
b : 1,
c: function() {
console.log(return this.b)
}
}
You cannot refer to other properties in the declaration as part of a Javascript literal declaration. So, in your Javascript literal declaration:
var a = {
b: 1,
c: this.b
};
this is not set to what you want and a has not yet been initialized yet so you can't refer to it either. There is simply no way to reach the other properties at the time of the literal declaration. This is a limitation of the current specification for Javascript. You could do this instead:
var a = {
b: 1
};
a.c = a.b;
because a is fully formed at that point so you can then reference other properties in it.
Or, in modern browsers, you could even use a getter to get the "live" version of b like this (which isn't exactly the same functionality as you were asking for since it's a "live" version of b that will track it's value), but shows you another possibility:
var a = {
b: 1,
get c() {
return b;
}
};
console.log(a.c); //results 1
In your second example:
var funcObj = {
b : function() {
return 1;
},
c: function() {
console.log(return this.b())
}
}
console.log(funcObj.c()) //results 1
You are calling funcObj.c() and that will set the value of this inside of c to funcObj so thus you can reference other properties via this.
The main difference here is that this is not set to the object inside of Javascript literal definition (your first example), but this is set to the object when you invoke a method as in funcObj.c().
I know this post is a bit old, but I came across it while trying to figure out how to solve a similar issue.
I was wanting to do something like:
const x = {
a: 12,
b: a + 1
}
console.log(x) //results undefined
(That's extremely simplified compared to what I was actually doing, but the principle is the same.)
My solution was to first create a function that would build the object I wanted, then pass in the primary value I was trying to act on (in this example, the value in 'a'):
function buildObj (val) {
const response = {
a: val,
b: val + 1
};
return response;
}
And then:
const x = buildObj(12)
console.log(x) // results { a: 12, b: 13 }
Once x has been initialized, any subsequent attempt to access
x.a
or
x.b
will return the values stored therein.
If a future searcher comes across this question because they're wanting to take an action on a value stored in a nested key within the same object, hopefully this will help.

Understanding pass by reference vs value with functions

As I understand objects are passed by reference in JavaScript (and primitives are passed by value?).
var a, b;
a = {
Foo: "Bar"
}
b = a;
a.Foo = "Other";
console.log(b.Foo); // "Other"
This worked similarly with arrays but did not work like I expect with functions:
var a, b;
a = function(){ return 20; }
b = a;
a = function(){ return 40; }
console.log(b()); // returns 20 ?
I'm confused because I thought functions are objects. Shouldn't the above example return 40?
In the first case, a.Foo = ..., You are changing the value of a property in the object, referred by both a and b. This is called mutating an object.
But in the second case, you are making a refer a new function object. Now, a and b are referring to different function objects.
That is why you are getting 20 in the second case.
First regarding the question in the title (which is actually different from what you demonstrate with the code examples):
"As I understand objects are passed by reference in JavaScript"
No, Javascript doesn't support passing parameter by reference at all. All parameters are passed by value, but the value can be a reference.
Example:
var a = { answer: 42 };
function f(x) {
alert(x.answer); // shows 42
x = { answer: 0 };
alert(x.answer); // shows 0
}
f(a);
alert(a.answer); // shows 42
As the parameter is passed by value, the variable x is separate from the variable a, so assigning a new object to x doesn't change the value of a.
Back to your code:
When you assign an object reference from a variable to another, it's the reference that is copied, not the object. You get two variables that reference the same object.
Either of the variables can be used to access members in the object, which your first code example demonstrates.
If you assign a new object to the first variable, you will replace the reference in the variable, you will not overwrite the object that it currently points to. The object is still intact, and the second variable still points to it. You get two variables that point to one object each, which your second code example demonstrates.
Further to #thefoutheye's answer, consider the following proof of your statement functions are objects:
var a, b;
a = function() { return 20; }
a.Foo = "Bar";
b = a;
a.Foo = "Other";
console.log(b.Foo); // "Other"
You are reassigning the variable a to a new function. That's not the same as changing a property value.
Try:
var a, b;
a = {Foo: function() {return 20;}};
b = a;
a.Foo = function() {return 40;};
console.log(b()); // returns 40

Can I reference other properties during object declaration in JavaScript? [duplicate]

This question already has answers here:
Self-references in object literals / initializers
(30 answers)
Closed 8 years ago.
I am trying to do something like this:
var obj = {
a: 5,
b: this.a + 1
}
(instead of 5 there is a function which I don't want to execute twice that returns a number)
I can rewrite it to assign obj.b later from obj.a, but can I do it right away during declaration?
No. this in JavaScript does not work like you think it does. this in this case refers to the global object.
There are only 3 cases in which the value this gets set:
The Function Case
foo();
Here this will refer to the global object.
The Method Case
test.foo();
In this example this will refer to test.
The Constructor Case
new foo();
A function call that's preceded by the new keyword acts as a constructor. Inside the function this will refer to a newly
created Object.
Everywhere else, this refers to the global object.
There are several ways to accomplish this; this is what I would use:
function Obj() {
this.a = 5;
this.b = this.a + 1;
// return this; // commented out because this happens automatically
}
var o = new Obj();
o.b; // === 6
This should return the correct values:
function () {
var aVar = 5;
var bVar = aVar + 1;
return {
a : aVar,
b : bVar;
}
}();
As it turns out you can't reference an object inside another object unless the first one is a function. But you can do it this way.
var obj = {
a: 5
}
obj.b = obj.a + 1; // create field b in runtime and assign it's value
If you console.log(obj) you will have
obj = {
a: 5,
b: 6
}
This way you keep the object literal structure for the remaining part of the code
No, in your example, the value of this doesn't refer to the object literal.
You'll need to assign a value to b after the object has been created in order to base it on another property in obj.
in chrome debugger
> var o = {a: 5, b: this.a+1}
undefined
> o.b
NaN
> o.a
5
No. this will take the same meaning as it would outside the definition.

Categories

Resources