Javascript constructor function - javascript

When trying executing the two following code blocks separately:
The first one:
function Hallo() {
}
var some_obj = {
name: "Fred",
age: 23,
}
Hallo.prototype = some_obj;
var obj = new Hallo();
obj.constructor;
And the second one:
function Hallo() {
}
Hallo.prototype.name = 'Khanh';
Hallo.prototype.age = 23;
var obj = new Hallo();
obj.constructor;
I got the result in firebug's console is "Object{}" for the first and "Hallo()" for the second.
While the second one is pretty simple to understand but the first one is really odd. Because as I know the constructor of the obj Object in the first one is still the same (that is Hallo() function).
However I got Object() function in result.
I really cann't understand why. Could you help me with it?
Thank you!

The reason is:
When you do var obj = new Hallo();, then
console.log(obj.constructor === Hallo.prototype.constructor); // true
In your first example, you assigned Hallo.prototype with a new object, whose constructor is function Object (function Object(){...}).
In your second example, the Hallo.prototype.constructor is still function Hallo() {...}

prototype will get a reference that point to the constructor by default, int the first function you overwrite the prototype to some_obj, the constructor reference changes at the same time to some_obj's constructor reference --Object's constructor Object()

Related

Call global function within a method?

I've done some leg work on getting this code to behave the way I want it to up to a certain point.
However I have encountered problem that requires a little bit of direction in helping me to solve the issue.
Problem to solve
Comments in code will explain what I am trying to archive..
var myArr = ["Brent white","brentw.white"];
function nameFoo (name){
var strSplit = name.split(" "); // splitting Brent White
var nameStr = this. myArr; // fetching Brent white string from myArr
console.log (strSplit,myArr[0]);
}
nameFoo("Brent White"); // calling nameFoo function
var myData = {
someData:"somedata",
someMoreData:"moredata",
myName:function(){
// I need to call nameFoo function through myName method.
// My hypothesis is that return will use the (this) keyword within the object?
}
};
// Here I need to call the method to have access my nameFoo? Correct me if I am wrong?
// Is this method invocation?
// Please help..Lost here...
To sum it up, I want myName method to call the nameFoo function. nameFoo will then give me myName method the result.
If someone could be kind enough to demonstrate how to get through this last step then I would be very grateful.
Pointing me in the right direction would also be greatly appreciated..
PS I am new to JS.
Be careful with the 'this' keyword. By calling nameFoo in a global context ie:
// some code
nameFoo(arg);
// some more code
'this' will always refer to 'window'. So, when you call myData.myName, even though this object calls the nameFoo method, 'window' will still be referenced in nameFoo's 'this'. 'this' is normally scoped to the object the function belongs to.
If you need 'this' to refer to one of your custom objects, use the Function prototype method "call" from within your myName function.
var myData = {
...
...
myName: function() {
nameFoo.call(this, someArgument);
};
Note that someArgument will be the argument passed to 'nameFoo' -- which will throw an error if you do not supply an argument. It's up to you to figure out what you want to pass.
More info about Function.prototype.call:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
More info about Function.prototype.apply:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
The only real difference between the two is how you supply arguments to the function you are calling. With "call", you separate the arguments with commas (as you would when normally executing a function).
eg: nameFoo.apply(this, arg1, arg2, arg3);
With "apply", you supply the arguments as an array.
eg: nameFoo.apply(this, [arg1, arg2, arg3]);
I'm thinking this conceptually may help you out:
// Some names in array
var my_names = ["Brent White", "John Smith"];
// Returns name array [First, Last]
function nameParse(full_name) {
return full_name.split(" ");
}
// Person object (properties)
function Person(name) {
this.full_name = name;
this.name_array = nameParse(name);
this.first_name = this.name_array[0];
this.last_name = this.name_array[1];
}
// Create single person example
var brent = new Person(my_names[0]);
// Access properties of brent
console.log(brent);
console.log("Hey, my first name is " + brent.first_name);
// Alternate example --------- //
// Store our people here
var my_people = [];
// Create a person for each name
for (var i = 0, max = my_names.length; i < max; i += 1) {
var some_person = new Person(my_names[i]);
my_people.push(some_person);
}
console.log(my_people);

javascript , use this.attrName in a function which name is also attrName

I found something strange..
function Man(){
this.Man = "Peter";
}
after I call it. (not use it as a constructor)
Man()
I think a result will be
alert(Man.Man)//-->Peter
but.. I'm wrong , actually the result is :
alert(Man.Man)//-->undefined
alert(Man)//-->Peter
That was really confusing ,how it happened??
I'll explain you what is happening there.
1
function Man(){
this.Man = "Peter";
}
The this in Man() function is window.
2
Man();
You are calling the function. Which sets the global variable Man's value to "Peter".
Note that this.Man = "Peter" is equal to window.Man = "Peter" as this is referring to the window.
3
alert(Man.Man)
The function call Man(); in step 2 has made the Man from a function to a string variable. Now Man is a variable whose value is a string and it doesn't contain the property Man, so it is undefined.
4
alert(Man)
Now, you are actually alerting the global variable which was created in Man() call and it was set the value of "Peter"
I used the chrome console and had some other findings
function Man(){
this.Man = "Peter";
console.log("this", this);
}
Above this refers to Window. If you call the function Man() nothing is returned since the function does not return anything but sets the property Man on the window-object to be Peter. Your line Man.Man should return undefined in chrome. If you use Man().Man you will get undefined as well since this refers to the window object and the function Man() has no property Man. You could write
function Man(){
this.Man = "Peter";
return this.Man;
}
This returns the value Peter. If you want to have a property Man you could use a constructor function write
// set this.Man == window.Man to Peter
function Man() { this.Man = "Peter"; }
// create an constructor for each object Man
Man.prototype = { constructor: this.Man }
// create an object
var man = new Man();
// call his property which was set in the constructor of the prototype
man.Man;
Please ask for more help if anything is unclear.
Update as response to the comment
You can use a constructor without using prototype (see examples at mdn or this question if you use this syntax:
function Box(color) // Constructor
{
this.color = color;
}
var redBox = new Box("red");
var blueBox = new Box("blue");
redBox.color; // returns red
blueBox.color; // returns blue
To understand where this refers to you can take a look at understanding javascript this. In the box-example this refers to the new instance (object) of the "underlying class function". In function Man(){this.Man = "Peter"} the this refers to this.window. You can read more about protype in this book.

Object prototype does not "live update"

I have the following piece of code:
var Test = function () {
};
Test.prototype.doSomething = function() {
return "done";
};
Now, I create an object of Test
var t = new Test();
alert(t.doSomething()); // Correct alerts "done"
Now I add another method to the prototype:
Test.prototype.fly = function() { return "fly"; };
alert(t.fly()); // Correctly alerts "fly" (existing objects get "live udpated")
Now, I make the prototype point to a blank object:
Test.prototype = {};
alert(t.doSomething()); // Continues to alert "done", but why?
alert(t.fly()); // Continues to alert "fly", but why?
var t2 = new Test();
alert(t.doSomething()); // As expected, this does not work
When I add a method to prototype, it reflects correctly on all new and existing objects
When I "blank" out the prototype by doing <name>.prototype = {};, it only "blanks" out new instances, but not existing ones. Why?
An analogy is this:
var a = {foo : 'bar'};
var b = a; //the same object as a
var c = a;
var d = a;
a.apple = 'orange';
a = 1; //a === 1. b, c and d stay the same, pointing to the object with apple
What I did here is replace what a was pointing, but not the object itself.
When you added fly, you are modifying that single prototype object which all instances share, the object that Test.prototype is currently pointing to.
But when you assigned a blank object to Test.prototype, you modified what Test.prototype was pointing to. It does not modify what the existing instances are pointing to. But from this point on, any new instances will now use the new object on Test.prototype as their prototype object.
If you are familiar with C, I'd rather think of JS variables as pointers rather than references.
I'm completing the previous answer, if you want reflect your changes on all instances you must update the prototype correctly.
Prototype property is an object and you can delete a propery with the reserved keyword 'delete'.
If you want delete 'doSomething' property :
delete Test.prototype.doSomething;
consider
function Foo(){}
Foo.prototype = {a:{"VMAddress":"#1234"}}
consider that Foo.prototype.a object has VMAddress "#1234"
if you create object now then,
var f1 = new Foo();
now f1.a will point to the same object ie with Virtual Machine address "#1234"
if you look
f1.a === Foo.prototype.a ;//prints tue
If you change prototype to some other value now,
Foo.prototype = {a:{"VMAddress":"#5678"}}
and if you create object now then,
var f2 = new Foo();
although
f2.a === Foo.prototype.a; //prints true because both point to same VM address #5678
but
f1.a === f2.a; //prints false
why??
because their VM address are different(one is #1234 and other is #5678) and infact they are different object
final verdict
the prototype chain at the time of object creation decides what an object's prototype will be.

prototype odd result when changing way to define

When trying to test prototype functionality, I got this odd result:
Here is my first test:
<script>
function Hello() {
}
var a = new Hello();
Hello.prototype.name = "Fred";
alert(a.name);
</script>
And, here's the second one:
<script>
function Hello() {
}
var a = new Hello();
Hello.prototype = {
name : "Fred",
}
alert(a.name);
</script>
I can't understand why the first will return a alert with "Fred" and the second is "undefined" though these mean the same thing?
Could you help me with it?
Thank you.
When you define a function in JavaScript, the interpreter makes a special prototype property available on the function, which points to an object, in case you use that function as a constructor. The [[Prototype]] internal property points to this object when you create a new object using the constructor.
When you replace the prototype property with a new one, you are replacing that reference, and if you do it after you instantiate an object, you will find the prototype object appears to be stale (that object's [[Prototype]] is pointing to the original object that prototype pointed to).
Solutions
Only assign new properties directly on the prototype property.
var constructor = function() { };
constructor.prototype.someMethod = function() { };
Use an extend type function to extend the existing prototype property with your new object (in this example, I used Underscore's extend() function).
var constructor = function() { };
_.extend(constructor.prototype, { someMethod: function() { } });
Make sure after the constructor, assigning the prototype property is the very next step in your program (generally not recommended).
var constructor = function() { };
constructor.prototype = { someMethod: function() { } };
Your ordering is messed up. You need assign the object to the prototype before using the new operator:
function Hello() {
}
Hello.prototype = {
name : "Fred",
}
var a = new Hello();
alert(a.name);​
Demo.
The two code snippets are not actually equal.
In the first script you only override Hello.prototype.name, while in the second script you override the whole content of Hello.prototype.

Invoking a function Object in JavaScript

I have a small question in JavaScript.
Here is a declaration:
function answerToLifeUniverseAndEverything() {
return 42;
}
var myLife = answerToLifeUniverseAndEverything();
If I do console.log(myLife), it will print 42, as I am just invoking the same instance of function resulting in 42 as the answer. (Basic rule on JavaScript that only references of objects are passed and not the object.)
Now, on the other, hand if I do:
var myLife = new answerToLifeUniverseAndEverything();
then I can't invoke the function; instead, myLife becomes just an object? I understand that this is a new copy of the same function object and not a reference, but why can't I invoke the method?
Can you please clarify the basic fundamental I am missing here?
By prefixing the call to answerToLifeUniverseAndEverything() with new you are telling JavaScript to invoke the function as a constructor function, similar (internally) to this:
var newInstance = {};
var obj = answerToLifeUniverseAndEverything.call(newInstance); // returs 42
if (typeof obj === 'object') {
return obj
} else {
return newInstance;
}
JavaScript proceeds to initialize the this variable inside the constructor function to point to a new instance of answerToLifeUniverseAndEverything. Unless you return a different Object yourself, this new instance will get returned, whether you like it or not.
When you do var myLife = answerToLifeUniverseAndEverything();, myLife is simply holding the return value from the function call - in this case, 42. myLife knows nothing about your function in that case, because the function was already called, returned, and then it assigned the resulting value (42) to the new variable myLife.
A completely different thing happens when you do var myLife = new answerToLifeUniverseAndEverything(); - instead, a new object is created, passed to the function as this, and then (assuming the function doesn't return an object itself), stored in the newly created variable. Since your function returns a number, not an object, the newly generated object is stored.
Try:
function answerToLifeUniverseAndEverything() {
return 42;
}
var myLife = answerToLifeUniverseAndEverything;
alert(myLife());
When you do:
var myLife = answerToLifeUniverseAndEverything();
you're assigning the function result to myLife ie 42.
I think i've described the behaviour of new elsewhere. Basically when you do new f() the JS engine creates an object and passes that as this, then uses that object if the return value of f() is not an object.
eg.
o = new f();
is equivalent (approximately) to
temp = {};
temp2 = f.call(temp);
o = typeof temp2 === "object" ? temp2 : temp;
If I do console.log(myLife) It'll print 42, as I am just invoking the same instance of function resulting in 42 as the answer. (Basic rule on javascripts that only references of objects are passed and not the object)
Not quite. This is because you're assigning the return value of answerToLifeUniverseAndEverything() to myLife. If you wanted to make a copy of the function, drop the brackets:
var myLife = answerToLifeUniverseAndEverything;
console.log(myLife());

Categories

Resources