javascript function this and prototype - javascript

The code is below:
function A() {
this.name = "kl";
this.obj2 = { a: 1 };
}
A.prototype.city = "china";
A.prototype.obj = {age: 30};
var a = new A();
var b = new A();
a.name = "kobe";
a.obj.age = 20;
a.city = "American"
a.obj2.a = 30;
console.log(b.name); // k1
console.log(b.city); // why china ?
console.log(b.obj); // when b.city = china, why b.obj = {age: 20}
console.log(b.obj2); // {a: 1}
My opinion is that a and b has its own this, so how you edit this[property] you can't change b its own this.value;
property declare so share property ? is right ?
but when obj is change will effect b.obj,
when city change will not effect b.city ?

Both objects have city and obj in their prototype chain. However, if you do a.city = "American" you are creating a new property city on a itself, shadowing the property city in the property chain.
Assigning to a property will (almost) always create that property on the object itself.
a.obj.age = 20; however reads (not assigns!) the object referenced by a.obj and updates its age property. a and b have the same prototype and thus a.obj and b.obj resolves to the same object. If the object is mutated in any way it will affect a and b in the same way.
Structure from the Chrome console:

Let's go through this line by line:
First of all, A.prototype points to an object.
When you run var a = new A();
You create a new object which is set to 'this'
This new object has properties name and obj2 which have values kl and { a: 1 }
this object is linked to the object A.prototype points to, thus a prototype chain is set up.
at the end of function A, the function actually runs return this;, which literally returns the object created to be assigned to a.
var b = new A(); does the same as above
when you run a.name = "kobe";, you're modifying the value from kl to kobe
when you run a.city = "American";, you're creating a new property city on a itself
and when you run a.obj2.a = 30;, you're also only modifying a value.
But when you run a.obj.age = 20;, something is different
a doesn't have the property obj on itself, so it goes up the prototype chain to the object A.prototype points to, and finds the property obj, so this line of code is actually modifying that obj, and changes the value of obj.age from 30 to 20.
when you execute b.name, since b has property name with value kl, so it prints kl
However, b doesn't have the property city on itself, so it goes up the prototype chain to the object A.prototype points to and see if it can find one, which it does, as previously you ran A.prototype.city = "china";, so it prints china.
When console.log(b.obj); is run, b goes up to the prototype chain and find obj on the object A.prototype points to, so it prints {age: 20}

Related

Arrays contain value call by Reference so their pointer should turn same values and equate to true

As far as I know, the arrays and objects always act as pointers and just point to somewhere a memory location.
In the following example, as var a is updated, so as b pointing to same memory location as a, should also be updated and final answer should be true, true.
Why is it not happening??? At what instance of time, b gets a different pointer than a and why???
Example:
var a = [2,3,5];
var b = a;
a = [33,45];
console.log(a,b);
console.log(a==b,a===b);
However, to support my clause kindly look at following unchanged values example. Here I am sure both a and b point to same memory location containing data as [2,3,5]. They got same values and are always equated as true.
var a = [2,3,5];
var b = a;
console.log(a==b,a===b);
Because you are not updating the reference of the new object [33, 45].
Following code might help you understand better.
a = [{'a': 1}, {'b': 2}];
b = a;
console.log(a, b);
// creates new object and assigns to the same variable
b = b.concat ([{'c': 3}]);
console.log(a, b);
// but property of object is still referenced in by a and b
b[0].a = 100;
console.log(a,b);
a[2].c = 100; // throws exception, because 'a' does not have the reference to object which refers the object created in 'b'
console.log(a,b);
look at blow:
var a = [2,3,5];
var b = a;
and after the a = [33,45];
the pointer is point to a new obj, not the obj changed

Does this example represent "Prototypal Inheritance"?

I have got an object literal (a), which I later use to make another object (b) add some properties, and again make an object with help of (b), ie (c) and add some properties to it.
Finally, I try access c.name which browser goes on for searching first in c, then b, then finally gets it from object a (same for second alert). But, I am a bit confused if this example correctly represents "Prototypal Inheritance"! (As, function constructure with prototype properties is not involved).
var a = {name: "Jenny", age: 27};
var b = Object.create(a);
b.state = "New York";
var c = Object.create(b);
c.flag = "50 star flag";
alert(c.name);
alert(b.age);
Yes, it does, the prototype chain you created is c -> b -> a.
var a = {};
var b = Object.create(a);
console.log(Object.getPrototypeOf(b) === a); // true
var c = Object.create(b);
console.log(Object.getPrototypeOf(c) === b); // true
If you're confused about missing constructor functions in this example, remember that Object.create is just a shortcut for
function Object.create(proto) {
function F() {}
F.prototype = proto;
return new F();
}
so the new and constructor are still executed under the hood. For the rationale behind Object.create see this classic article.

Copied object generated by Object.Assign() function has side effect?

I have an object named result which is composed of two objects like :
const a = {bar: {baz: 2}};
var b = {foo: 1};
var result = Object.assign({}, a, b);
console.log(result, a, b);
// result -> {bar: {baz: 2}, foo: 1}
// a -> {bar: {baz: 2}}
// b -> {foo: 1}
Now, I am changing the bar property of the result object like:
result.bar.baz = 3;
result.foo = 4;
console.log(result, a, b);
// result -> {bar: {baz: 3}, foo: 4}
// a -> {bar: {baz: 3}} intresting part
// b -> {foo: 1} intresting, too!
(You can copy and paste code to javascript console in order to see the result for both cases by the way)
There are two weird things here. First one is that I am changing the resulting object's property, but constant object a's property changes, too. Even if first one is the case with Object.assign function, how can I change the constant variable? Let's say this is the case despite const variable mutation, then why the change in property foo does not reflect to the object b?
I came with that because I generally use Object.assign to copy objects, but this is pretty weird issue with that function I guess. Any ideas about the case? Thank you.
Declaring a variable with const only prevents it from being changed to another value. It doesn't prevent the data referenced by that value to change.
const foo = {prop: 'bar'};
foo.prop = 'baz'; // Works well
foo = 'baz'; // TypeError: invalid assignment to const `foo'
If you want to prevent an object from being changed, you can freeze it.
Object.freeze(foo);
foo.prop = 'buz'; // TypeError: "prop" is read-only
However, that will only affect own properties. If the value of one of these is another object, it won't become frozen.
This is what happens with Object.assign too. It only copies own properties, and if their value is an object, it won't "clone" it. That is, the references will still be the same, and changes will be reflected.
If you want to deeply clone an object, see What is the most efficient way to clone an object?
Object.assign will work but with the added gotcha that if any of the properties you are assigning from contain an object as a value it does not create a copy of that object, so the references do not change, the property in the created object will point to that same nested object.
Also constant in javascript can be deceiving, you can add and remove properties from a 'const' object as long as you don't try to reassign it to a new object or a different primitive.
Same will occur with arrays, you can create a 'const' array but push pop off of it.
https://jsfiddle.net/eu9yg37s/6/ just something I was messing around in to attempt to display what I mean.
const a = {bar: {baz: 2}};
var b = {foo: 1};
// Example of customizer function that may take into account nested objects and properly copy them using lodash 4.x
var customizer = function(objValue, srcValue) {
if (typeof srcValue === 'object' && typeof srcValue !== null) {
return _.assignWith({}, srcValue, customizer);
}
return _.isUndefined(objValue) ? srcValue : objValue;
}
// This calls assign, but will invoke the customizer function
var result = _.assignWith({}, a, b, customizer);
result.bar.baz = 3;
result.foo = 4;
console.log(result, a, b);
// 'Constant' Array Example
const hi = [true, false, 'hi'];
hi[2] = 23;
console.log('hi.pop', hi.pop());
console.log('hi', hi);
// These will error, uncomment out to see it errors on any of these attempts
//hi = 3;
//hi = 'no';
hi = [true, false, 23];
//hi = false;
//hi = {};
The change doesn't reflect in b, because it wasn't a nested object during the assign operation so the property foo in our created object is pointing to a new primitive 1

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

Why and how __proto__ remembers old properties of the constructor function's undefined prototype member?

Quick Note: Please don't explain basics of javascript inheritance in your answer.
Here is simple constructor function with some properties attached to it's prototype member.
function Foo() {
this.relationship = "Love";
};
Foo.prototype.name = "Natalie";
Foo.prototype.age = 22;
Foo.prototype.country = "France";
Now we create new object with Foo and test some basics. Everything is cool.
var girl = new Foo();
girl.hasOwnProperty("relationship"); //=> true
girl.hasOwnProperty("name"); //=> false
girl.relationship; //=> "Love"
girl.name; //=> "Natalie", this comes from Foo.prototype
girl.__proto__ === Foo.prototype; //=> true
girl.__proto__.name === Foo.prototype.name; //=> true
girl.name === Foo.prototype.name; //=> true
And if we update the value of Foo.prototype.name property, girl.name points to new value as it should.
Foo.prototype.name = "Lucia";
girl.name; //=> "Lucia", this comes from Foo.prototype
Mysterious thing happens when we change Foo.prototype and make it null, undefined, empty object etc.
Foo.prototype = null;
If our girl object had a hidden __ proto__ (ECMA [[Prototype]]) link to Foo.prototype, then after making Foo.prototype null there should be no chance for girl to get name property, but it does!
girl.name; //=> "Lucia"
girl.age; //=> 22
girl.country; //=> "France"
Now if we create another object with Foo at this point. It doesn't have name, age and country, because, of course, Foo.prototype is null.
var new_girl = new Foo();
new_girl.name; //=> undefined
new_girl.age; //=> undefined
new_girl.country; //=> undefined
So my question is how on earth previous object (girl) and his hidden __ proto__ link can remember those properties after we assigned Foo.prototype to null?
It's not mysterious at all, and it has nothing to do with inheritance.
It has to do with object-pointers/references.
var a = { name : "Bob", age : 32 };
var b = a;
b.name; // "Bob";
a.name = "Jim";
b.name; // "Jim";
a = null;
b.name; // "Jim";
What happened?
a and b were given pointers to the same object.
As you changed the properties of the object, by referencing one or the other (it doesn't matter if you change them on a or on b), the other reference will see the changes, too.
You aren't making new objects which have the same properties and values, you're just giving them both the address of the same object, and they're looking up the properties every time you ask them.
Then you reassign a.
You're not changing the object, you're giving a an address to some other place.
b still has the address.
So now think of it this way:
function Foo () { }
Foo.prototype = { name : "Bob", age : 32 };
var a = new Foo();
var b = new Foo();
a.__proto__ === Foo.prototype;
b.__proto__ === Foo.prototype;
Foo.prototype.age = 35;
a.age; // 35
b.age; // 35
// now we're replacing the `.prototype` reference with a brand new object
Foo.prototype = { name : "Sally", age : 16 };
a.__proto__ !== Foo.prototype;
b.__proto__ !== Foo.prototype;
a.name; // "Bob"
b.age; // 35
All the constructor is doing in the background is saying:
this.constructor = arguments.callee;
this.__proto__ = this.constructor.prototype;
So when you change properties on the object referenced by both this.constructor.prototype and this.__proto__ lookups on either will find the new values.
But removing a reference from one won't delete the object for the other.
If that's the result you want, then you'd need to erase each property of the prototype (doesn't matter where you do it from -- from the function or from any of the instances) and then nullify the .prototype by setting it to an empty object (null would cause errors on lesser browsers), so future objects have no access.

Categories

Resources