I have a question about this fonction:
var MyObject3 = function (a, b) {
var obj = { myA : a, myB : b } ;
obj.foo = function () { return obj.myA + obj.myB ; } ;
obj.bar = function (c) { return obj.myA + c ; } ;
return obj ;
} ;
obj.foo and obj.bar are closures(what i understand). I write first:
obj3 = MyObject3(1, 2) ;
and the result is: {"myA" :1,"myB" :2}. This is OK. I try to change the value of obj3.myA : > obj3.myA = 4 ; obj3 ; and the result is : {"myA" :4,"myB" :2} . What I don't understand is: why > obj3.foo() ; returns 6? obj3.foo() gives 6 as a result ? obj3.foo() is supposed to be a closure isn'it ? its result should be;3 ?
Function MyObject3 defines a variable in its scope, which refers to a newly created object:
var obj = { myA : a, myB : b } ;
All references to obj inside of that function's scope refer to that object. Than the object is returned by the function and saved to the variable obj3. obj inside of the MyObject3 scope and obj3 in the global scope thus refer to the same object.
In javascript, primitives (e.g. numbers, booleans, strings) are passed by value, whereas objects are passed by reference. Which means that:
var val1 = 1;
var val2 = val1;
val1 = 4;
console.log(val2); // will log 1
// but:
var obj1 = {foo: 'bar'};
var obj2 = obj1;
obj1.foo = 'baz';
console.log(obj2.foo); // will log 'baz'
Related
I was looking into how to create a dynamic nested objects from a string, for example, a string "obj1.obj2.obj3.obj4", how do you turn that into nested objects with the same order.
I googled around and i found this nice and clean code, but i did not understand how it worked, and there was no explanation on the page where it was written, can someone explain how this works please?
here is the code:
var s = "key1.key2.key3.key4";
var a = s.split('.');
var obj = {};
var temp = obj;
for (var k =0; k < a.length; k++) {
temp = temp[a[k]] = {};
console.log(temp);
}
console.log(obj);
why is there a var temp = obj?
what does this line do?:
temp = temp[a[k]] = {};
also, the console.log(temp) inside the loop always logs an empty object {}, why?
Thanks for the feedback!
why is there a var temp = obj?
obj is a variable to hold the completed object. temp is a variable to hold each intermediate step of the object being built. temp starts out with the same value as obj so that the first iteration of the loop adds on to obj.
what does this line do?:
temp = temp[a[k]] = {};
Assign an empty object to a property in temp with the name a[k], where a[k] is one of the values in a.
Assign that new empty object to temp.
This could be written separately as two lines:
temp[a[k]] = {};
temp = temp[a[k]];
also, the console.log(temp) inside the loop always logs an empty object {}, why?
Because the previous line assigns an empty object to temp.
Your question boils down to this (comments inline)
var x = {};
var y = x;
y[ "a" ] = {}; //reference to x stays so x also becomes { "a": {} }
y = y["a"]; //now y effectively becomes {} but has the same reference to y["a"] as assignment works right to left hence property `a` is becomes non-enumerable and hence shadowed.
console.log( "First Run" );
console.log( y ); //prints {}
console.log( x ); //prints { "a": {} }
y[ "a" ] = {}; //y still has a non-enumerable property `a`
y = y["a"]; //same as above y = y["a"], y again becomes {}
console.log( "Second Run" );
console.log( y ); //prints {} again
console.log( x ); //prints { "a": { "a": {} } }
Outputs
First Run
{}
{ "a": {} }
Second Run
{}
{ "a": {
"a": {} } }
Have added comments in code, hope it will be useful
var s = "key1.key2.key3.key4";
//split the string by dot(.) and create an array
var a = s.split('.');
//Creating an empty object
var obj = {};
var temp = obj;
//looping over the array
for (var k = 0; k < a.length; k++) {
//a[k] will be key1,key2,key3....
// temp is an object,square bracket is use to create a object key
// using a variable name
// variable name here is key1,key2....
//temp[a[k]] will initialize an empty object
temp = temp[a[k]] = {};
console.log(temp);
}
console.log(obj);
It seems where you are iterating the array, in that temp object is newly creating and assigning key to obj.
temp = temp[a[k]] = {};
above line simply assigns a[index] value as a key to the new object and as a reference to obj the nested object is created.
for your question,
why is there a var temp = obj?
it copies obj object into temp variable
also, the console.log(temp) inside the loop always logs an empty object {}, why?
since you are recreating an empty object (or reassigning).
var A = [];
var obj = {
x: A[1],
y: 'hello'
};
A[1] = 1;
console.log(JSON.stringify(obj)); // {"y":"hello"}
By the time I'm using obj in console.log(), A[1] has already been defined.
How can I get the "latest" obj, with all its properties updated ? Such that we get {"x":1,"y":"hello"} when we do console.log() ?
You are getting the latest object. If you want the x property to update as its assigned value changes throughout the runtime of the code you need to use an object, since it will just store a reference to it and as the place in memory changes you will see those changes everywhere you assigned it. Arrays are considered objects so you could just assign A to x.
var A = [];
var obj = {
x: A,
y: 'hello'
};
A[1] = 1;
alert(JSON.stringify(obj));
Another example using an object as value:
var A = [];
var B = {};
A[1] = B;
var obj = {
x: A[1],
y: 'hello'
};
B.z = 1;
alert(JSON.stringify(obj));
A[1] = 1; is actually defined when obj was already constructed. So obj.x is always undefined.
var A = [];
A[1] = 1;
var obj = {
x: A[1],
y: 'hello'
};
document.body.textContent = JSON.stringify(obj);
Assuming you want the value of obj.x as a primitive :
It's not possible to assign the reference of a var to obj.x.You can make obj.x as a function that'll get the latest value of that variable
var variable= 2
var obj = {
x: function() {
return variable;
},
y: 'hello'
};
variable = 5;
console.log(obj.x()); //prints 5
Javascript objects are not reinitialised by reference.
You need to do obj.x = 1 to update the object.
Is it possible to use getters/setters on Javascript objects like the following basic functionality mockup?
function Descriptor(x) {
this._value = x;
this.setter = function(x) {
// Set internal value after some action or modification
this._value = x + 1;
}
this.getter = function() {
// Return the internal value
return this._value;
}
}
var obj = {};
obj.a = new Descriptor();
obj.a = 5; // Would run the setter defined in the Descriptor object
obj.a == 6; // Should evaluate to true in this trivial example
// Same as above, just an example of being able to easily reuse the getter/setter
obj.b = new Descriptor();
obj.b = 10;
obj.b == 11;
Ultimately, it should operate similarly to a Python descriptor set in a class definition. The only things I can find that accomplish something like this requires that the getter/setter be hooked up during the above obj creation, and cannot be easily reused on multiple attributes or objects.
You can try ES5 Object.defineProperty:
function addDescriptor(obj, prop) {
var value = 0;
Object.defineProperty(obj, prop, {
get: function(x) {
return value;
},
set: function(x) {
value = x + 1;
}
});
}
var obj = {};
addDescriptor(obj, 'a');
obj.a = 5;
obj.a == 6; // true
addDescriptor(obj, 'b');
obj.b = 10;
obj.b == 11; // true
I don't know what your environment is (it's only tagged javascript), but ES6 Proxies provide this flexibility of get/set
copied from MDN:
var handler = {
get: function(target, name){
return name in target?
target[name] :
37;
}
};
var p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;
console.log(p.a, p.b); // 1, undefined
console.log('c' in p, p.c); // false, 37
You can either use Object.defineProperty to define getter and setter, or simply do it in an object initialiser:
var obj = {
value: 0,
get a(){
return this.value;
},
set a(x){
this.value = x + 1;
}
};
I believe you are trying to do something like this: (Another way of doing what Oriol has done in his answer.)
Object.prototype.Descriptor = function(name){
var value = 0;
Object.defineProperty(this, name, {
get: function(){ return value; },
set: function(x){ value = x + 1; }
});
};
var obj = {};
obj.Descriptor("a");
obj.Descriptor("b");
obj.a = 5;
obj.b = 10;
obj.a //6
obj.b //11
obj.value //undefined
Everything is separated, such that the function can be reused meanwhile values are kept separated from all other object's value.
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);
when constructing an object using methods from other objects as an attribute name get Syntax Error: Unexpected token . - cannot find correct syntax
var R = function(a) { this.arg = a; };
R.prototype.name = function() { return this.arg; }
var r1 = new R('abc');
var name1 = r1.name(); // => "abc"
var o1 = { 'abc': r1 } // this works with constant
var o2 = { name1: r1 } // does not work with variable (see answer)
var o3 = { r1.name(): r1 } // this fails - syntax
var o4 = { 'abc': r1.name() } // this works
have tried { (r1.name()): r1 }, but that fails as well.
please note that strings and integers are evaluated as barewords whereas methods and variables are not:
var o5 = { e.1: 123 } // fails
var o6 = { 'e.1': 123 } // succeeds
var o7 = { 1: 123 } // succeeds
var o8 = { '1': 123 } // same as o7
var o2 = { name1: r1 } // this works with variable
This has the same meaning as:
var o2 = { 'name1': r1 }
In other words, it's still treating name1 as a literal string. The key in an object literal must be a constant or a so-called "bareword" -- this is a restriction of the language. Variables and function invocations cannot be used as keys in object literals (but they can be used as values). Using variables will appear to work, but the variable name will be used as the key and not the variable's value.
You will have to do something like:
var o2 = {};
o2[name1] = r1;
var o3 = {};
o3[r1.name()] = r1;
var o4 = { 'abc', r1.name() }
this one should be:
var o4 = { 'abc': r1.name() }
You could create your own property setter
function setProperty (prop,val,obj) {
if (typeof prop === "undefined" || typeof val === "undefined") return undefined;
if (typeof obj === "undefined") obj = {};
obj[prop] = val;
return obj;
}
// use 1
var o1 = setProperty(r1.name(),r1);
// use 2
var o2 = {};
setProperty(r1.name(),r1,o2);