How does 'this' work in JavaScript? - javascript

I know there are several other posts on this topic but they still leave me confused.
I've included jQuery and everything and,
I have a simple javascript class like this example:
function CarConstructor(){
this.speed=19; // in mph
this.make="Ford";
this.fillKph=fillKph;
}
function fillKph(){
$("#kphdiv").html(this.speed*1.61);
}
car1 = new CarConstructor();
car1.fillKph();
Now I know that that code snippet doesn't work and is not properly consturcted.
The "this" keyword there is referencing my dom element with the id of "kphdiv".
The question I have is what is the best way to handle this.
Ive seen one method where you set some variable equal to this (binding it) and then use that variable to reference your object. For example:
function CarConstructor(){
this.speed=19; // in mph
this.make="Ford";
this.fillKph=fillKph;
}
function fillKph(){
var me=this;
$("#kphdiv").html(me.speed*1.61);
}
car1 = new CarConstructor();
car1.fillKph();
I could also make the me a global variable ... I don't know.
I was just curious if there is another/better way.

Oh boy, you are confusing quite a few things.
function CarConstructor(){
this.speed=19; // in mph
this.make="Ford";
this.fillKph; // <-> This particular statement has no meaning.
//When you write this.fillKph without any assignment, it will be 'undefined'.
//Just because you have a function named 'fillKph' somewhere else,
//it doesn't mean it will get attached to this property.
}
Try,
var toyota = new Car();
alert(typeof toyota.fillKph); //will alert undefined.
The fillKph function is created in global scope, i.e. as property of 'Window' object.
function fillKph(){
var me=this;
$("#kphdiv").html(me.speed*1.61);
}
To fix it, you can what rezzif suggested. Your final code will look like
function Car()
{
this.speed=19; // in mph
this.make="Ford";
this.fillKph = function (){
$("#kphdiv").html(this.speed*1.61);
};
}
car1 = new Car();
car1.fillKph();
If you notice, I did not store reference to 'this' inside a local variable. Why? There is no need in this scenario. To understand more, see my detailed answer here.
If you are going to create lot of Car objects, you can define the fillKph method on the prototype.
function Car()
{
this.speed=19; // in mph
this.make="Ford";
}
Car.prototype.fillKph = function fillKph() { $("#kphdiv").html(this.speed*1.61); };
car1 = new Car();
car1.fillKph();
EDIT:
If you do something like,
function CarConstructor(){
this.speed=19; // in mph
this.make="Ford";
this.fillKph = fillKph;
}
function fillKph(){
$("#kphdiv").html(me.speed*1.61);
}
car1 = new Car();
car1.fillKph(); //This will work as expected.
But the problem is that fillKph is defined in 'Window' scope, so I can directly call it like,
fillKph(); //Calling it this way will break it as it won't get correct 'this'.
Point is,
alert(typeof fillKph); // alerts 'function' if you do it your way,
alert(typeof fillKph); // alerts 'undefined', if you do it the way I suggested, which is preferred in my opinion.

function CarConstructor(){
var _this = this;
this.speed=19; // in mph
this.make="Ford";
this.fillKph = function (){
$("#kphdiv").html(_this.speed*1.61);
};
}
car1 = new CarConstructor();
car1.fillKph();

There's completely nothing wrong with the latter method, it's perfectly fine and probably the most elegant way of doing it, it just stores a reference to the execution context in that point and time for use in another execution context where the reference points to a different object.

The confusing thing about this in javascript is it's relationship to the new operator. As you walk up the scope chain, this always refers to the last occruance of new. If need be, that means going all the way back to the window object. So if you have something like this:
function MyObject()
{
this.baz = "some value";
this.bar = function() { return this.baz; }
}
var foo = new MyObject();
alert(foo.bar());
it works as expected, because the foo variable was created with a new object/scope for the this keyword, and so the reference to this.baz points to the right place.
But then if you do this:
var foo = new MyObject();
var bar = foo.bar;
alert(bar());
expecting to call foo's bar function, you're now calling it outside of the "scope" created for foo by the new operator. Your use of this inside the bar function now looks at the window object, which doesn't have a definition for baz.
That may seem like an edge case, but it's important when working with frameworks like jQuery that create a lot of implicit objects using new or that expect you to pass functions around like variables. You have to be very careful.

Related

whats the difference between closures and this

I am just getting more into javascript and wandering what is the difference between
var myfunc = function(){
publicfunctions = {}
publicfunctions.function1 = function(){do smthing and return}
return publicfunctions
}
and
var myfunc = function(){
this.function1 = function(){do smthing and return}
}
It seems to me that both doing the same thing
Also can someone explain what is difference between
var func = (function myfunc(){ .. do smthing and return .. })();
and
var func = function myfunc(){ .. do smthing and return .. }
var newfunc = new myfunc()
Thanks
Let's go step by step.
example:
a) you define a function that returns an object (careful with variable declaration - you should declare it with var keyword in order to scope it to your function. That objects has a single property that points to a function. Never the less, your first function is assigned to a variable myfunc
Now, if you try to call myfunc(), you'll get an object with single property function1. Nothing special here.
b) you define a function again and assign it to myfunc variable, only this time it contains this keyword which assumes you're trying to utilize this function as a constructor. In this example, merely calling myfunc produce no output since you haven't returned anything from a function. However, calling a function with preceding keyword new will result in object creation.
var myObj = new myfunc();
// `this` keyword now refers to myObj which means myObj can call `function1`
example:
a) On the righthand side is something that is called IIFE (or Immediately Invoked Function Expression). Basically means, a function expression that is created and executed, well, immediately. So func should receive whatever that function returns.
b) Yet again, facing a constructor, only this time you actually assumed myfunc is a constructor when you added new keyword before myfunc execution. Creates an object to whic newfunc now points to and has authority over.
Note:
In constructor functions (the ones that you call with new keyword), this is implicitly returned and no need for explicit return. Now, if you want to test it and return something else instead, I'll leave it up to you to explore and see what you'll end up with. :)
Since it's a broader topic in itself, I recommend this excellent book by Nicholas Zakas. It really answers a lot of JS questions.

How to get name of variable/object that has been pushed into an array? [duplicate]

Let's say I instantiate an object in Javascript like this:
var myObj = new someObject();
Now, is it possible to obtain the var object's name as string 'myObj' from within one of the class methods?
Additional details (edited):
The reason why I would like to get the name of the variable holding reference to the object is that my new myObj would create a new clickable DIV on the page that would need to call a function myObj.someFunction(). As I insert the new DIV I need to know the name of the variable holding reference to the object. Is there maybe a better way of doing this?
You are right, sorry for the mixup in terminology.
The reason why I would like to get the name of the variable holding reference to the object is that my new myObj would create a new clickable DIV on the page that would need to call a function myObj.someFunction(). As I insert the new DIV I need to know the name of the variable holding reference to the object. Is there maybe a better way of doing this?
Shog9 is right that this doesn't make all that much sense to ask, since an object could be referred to by multiple variables. If you don't really care about that, and all you want is to find the name of one of the global variables that refers to that object, you could do the following hack:
function myClass() {
this.myName = function () {
// search through the global object for a name that resolves to this object
for (var name in this.global)
if (this.global[name] == this)
return name
}
}
// store the global object, which can be referred to as this at the top level, in a
// property on our prototype, so we can refer to it in our object's methods
myClass.prototype.global = this
// create a global variable referring to an object
var myVar = new myClass()
myVar.myName() // returns "myVar"
Note that this is an ugly hack, and should not be used in production code. If there is more than one variable referring to an object, you can't tell which one you'll get. It will only search the global variables, so it won't work if a variable is local to a function. In general, if you need to name something, you should pass the name in to the constructor when you create it.
edit: To respond to your clarification, if you need to be able to refer to something from an event handler, you shouldn't be referring to it by name, but instead add a function that refers to the object directly. Here's a quick example that I whipped up that shows something similar, I think, to what you're trying to do:
function myConstructor () {
this.count = 0
this.clickme = function () {
this.count += 1
alert(this.count)
}
var newDiv = document.createElement("div")
var contents = document.createTextNode("Click me!")
// This is the crucial part. We don't construct an onclick handler by creating a
// string, but instead we pass in a function that does what we want. In order to
// refer to the object, we can't use this directly (since that will refer to the
// div when running event handler), but we create an anonymous function with an
// argument and pass this in as that argument.
newDiv.onclick = (function (obj) {
return function () {
obj.clickme()
}
})(this)
newDiv.appendChild(contents)
document.getElementById("frobnozzle").appendChild(newDiv)
}
window.onload = function () {
var myVar = new myConstructor()
}
Short answer: No. myObj isn't the name of the object, it's the name of a variable holding a reference to the object - you could have any number of other variables holding a reference to the same object.
Now, if it's your program, then you make the rules: if you want to say that any given object will only be referenced by one variable, ever, and diligently enforce that in your code, then just set a property on the object with the name of the variable.
That said, i doubt what you're asking for is actually what you really want. Maybe describe your problem in a bit more detail...?
Pedantry: JavaScript doesn't have classes. someObject is a constructor function. Given a reference to an object, you can obtain a reference to the function that created it using the constructor property.
In response to the additional details you've provided:
The answer you're looking for can be found here: JavaScript Callback Scope (and in response to numerous other questions on SO - it's a common point of confusion for those new to JS). You just need to wrap the call to the object member in a closure that preserves access to the context object.
You can do it converting by the constructor to a string using .toString() :
function getObjectClass(obj){
if (typeof obj != "object" || obj === null) return false;
else return /(\w+)\(/.exec(obj.constructor.toString())[1];}
You might be able to achieve your goal by using it in a function, and then examining the function's source with toString():
var whatsMyName;
// Just do something with the whatsMyName variable, no matter what
function func() {var v = whatsMyName;}
// Now that we're using whatsMyName in a function, we could get the source code of the function as a string:
var source = func.toString();
// Then extract the variable name from the function source:
var result = /var v = (.[^;]*)/.exec(source);
alert(result[1]); // Should alert 'whatsMyName';
If you don't want to use a function constructor like in Brian's answer you can use Object.create() instead:-
var myVar = {
count: 0
}
myVar.init = function(n) {
this.count = n
this.newDiv()
}
myVar.newDiv = function() {
var newDiv = document.createElement("div")
var contents = document.createTextNode("Click me!")
var func = myVar.func(this)
newDiv.addEventListener ?
newDiv.addEventListener('click', func, false) :
newDiv.attachEvent('onclick', func)
newDiv.appendChild(contents)
document.getElementsByTagName("body")[0].appendChild(newDiv)
}
myVar.func = function (thys) {
return function() {
thys.clickme()
}
}
myVar.clickme = function () {
this.count += 1
alert(this.count)
}
myVar.init(2)
var myVar1 = Object.create(myVar)
myVar1.init(55)
var myVar2 = Object.create(myVar)
myVar2.init(150)
// etc
Strangely, I couldn't get the above to work using newDiv.onClick, but it works with newDiv.addEventListener / newDiv.attachEvent.
Since Object.create is newish, include the following code from Douglas Crockford for older browsers, including IE8.
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o
return new F()
}
}
As a more elementary situation it would be nice IF this had a property that could reference it's referring variable (heads or tails) but unfortunately it only references the instantiation of the new coinSide object.
javascript: /* it would be nice but ... a solution NOT! */
function coinSide(){this.ref=this};
/* can .ref be set so as to identify it's referring variable? (heads or tails) */
heads = new coinSide();
tails = new coinSide();
toss = Math.random()<0.5 ? heads : tails;
alert(toss.ref);
alert(["FF's Gecko engine shows:\n\ntoss.toSource() is ", toss.toSource()])
which always displays
[object Object]
and Firefox's Gecko engine shows:
toss.toSource() is ,#1={ref:#1#}
Of course, in this example, to resolve #1, and hence toss, it's simple enough to test toss==heads and toss==tails. This question, which is really asking if javascript has a call-by-name mechanism, motivates consideration of the counterpart, is there a call-by-value mechanism to determine the ACTUAL value of a variable? The example demonstrates that the "values" of both heads and tails are identical, yet alert(heads==tails) is false.
The self-reference can be coerced as follows:
(avoiding the object space hunt and possible ambiguities as noted in the How to get class object's name as a string in Javascript? solution)
javascript:
function assign(n,v){ eval( n +"="+ v ); eval( n +".ref='"+ n +"'" ) }
function coinSide(){};
assign("heads", "new coinSide()");
assign("tails", "new coinSide()");
toss = Math.random()<0.5 ? heads : tails;
alert(toss.ref);
to display heads or tails.
It is perhaps an anathema to the essence of Javascript's language design, as an interpreted prototyping functional language, to have such capabilities as primitives.
A final consideration:
javascript:
item=new Object(); refName="item"; deferAgain="refName";
alert([deferAgain,eval(deferAgain),eval(eval(deferAgain))].join('\n'));
so, as stipulated ...
javascript:
function bindDIV(objName){
return eval( objName +'=new someObject("'+objName+'")' )
};
function someObject(objName){
this.div="\n<DIV onclick='window.opener."+ /* window.opener - hiccup!! */
objName+
".someFunction()'>clickable DIV</DIV>\n";
this.someFunction=function(){alert(['my variable object name is ',objName])}
};
with(window.open('','test').document){ /* see above hiccup */
write('<html>'+
bindDIV('DIVobj1').div+
bindDIV('DIV2').div+
(alias=bindDIV('multiply')).div+
'an aliased DIV clone'+multiply.div+
'</html>');
close();
};
void (0);
Is there a better way ... ?
"better" as in easier? Easier to program? Easier to understand? Easier as in faster execution? Or is it as in "... and now for something completely different"?
Immediately after the object is instantiatd, you can attach a property, say name, to the object and assign the string value you expect to it:
var myObj = new someClass();
myObj.name="myObj";
document.write(myObj.name);
Alternatively, the assignment can be made inside the codes of the class, i.e.
var someClass = function(P)
{ this.name=P;
// rest of the class definition...
};
var myObj = new someClass("myObj");
document.write(myObj.name);
Some time ago, I used this.
Perhaps you could try:
+function(){
var my_var = function get_this_name(){
alert("I " + this.init());
};
my_var.prototype.init = function(){
return my_var.name;
}
new my_var();
}();
Pop an Alert: "I get_this_name".
This is pretty old, but I ran across this question via Google, so perhaps this solution might be useful to others.
function GetObjectName(myObject){
var objectName=JSON.stringify(myObject).match(/"(.*?)"/)[1];
return objectName;
}
It just uses the browser's JSON parser and regex without cluttering up the DOM or your object too much.

Getting the name of a variable from within the variable. (JS) [duplicate]

Let's say I instantiate an object in Javascript like this:
var myObj = new someObject();
Now, is it possible to obtain the var object's name as string 'myObj' from within one of the class methods?
Additional details (edited):
The reason why I would like to get the name of the variable holding reference to the object is that my new myObj would create a new clickable DIV on the page that would need to call a function myObj.someFunction(). As I insert the new DIV I need to know the name of the variable holding reference to the object. Is there maybe a better way of doing this?
You are right, sorry for the mixup in terminology.
The reason why I would like to get the name of the variable holding reference to the object is that my new myObj would create a new clickable DIV on the page that would need to call a function myObj.someFunction(). As I insert the new DIV I need to know the name of the variable holding reference to the object. Is there maybe a better way of doing this?
Shog9 is right that this doesn't make all that much sense to ask, since an object could be referred to by multiple variables. If you don't really care about that, and all you want is to find the name of one of the global variables that refers to that object, you could do the following hack:
function myClass() {
this.myName = function () {
// search through the global object for a name that resolves to this object
for (var name in this.global)
if (this.global[name] == this)
return name
}
}
// store the global object, which can be referred to as this at the top level, in a
// property on our prototype, so we can refer to it in our object's methods
myClass.prototype.global = this
// create a global variable referring to an object
var myVar = new myClass()
myVar.myName() // returns "myVar"
Note that this is an ugly hack, and should not be used in production code. If there is more than one variable referring to an object, you can't tell which one you'll get. It will only search the global variables, so it won't work if a variable is local to a function. In general, if you need to name something, you should pass the name in to the constructor when you create it.
edit: To respond to your clarification, if you need to be able to refer to something from an event handler, you shouldn't be referring to it by name, but instead add a function that refers to the object directly. Here's a quick example that I whipped up that shows something similar, I think, to what you're trying to do:
function myConstructor () {
this.count = 0
this.clickme = function () {
this.count += 1
alert(this.count)
}
var newDiv = document.createElement("div")
var contents = document.createTextNode("Click me!")
// This is the crucial part. We don't construct an onclick handler by creating a
// string, but instead we pass in a function that does what we want. In order to
// refer to the object, we can't use this directly (since that will refer to the
// div when running event handler), but we create an anonymous function with an
// argument and pass this in as that argument.
newDiv.onclick = (function (obj) {
return function () {
obj.clickme()
}
})(this)
newDiv.appendChild(contents)
document.getElementById("frobnozzle").appendChild(newDiv)
}
window.onload = function () {
var myVar = new myConstructor()
}
Short answer: No. myObj isn't the name of the object, it's the name of a variable holding a reference to the object - you could have any number of other variables holding a reference to the same object.
Now, if it's your program, then you make the rules: if you want to say that any given object will only be referenced by one variable, ever, and diligently enforce that in your code, then just set a property on the object with the name of the variable.
That said, i doubt what you're asking for is actually what you really want. Maybe describe your problem in a bit more detail...?
Pedantry: JavaScript doesn't have classes. someObject is a constructor function. Given a reference to an object, you can obtain a reference to the function that created it using the constructor property.
In response to the additional details you've provided:
The answer you're looking for can be found here: JavaScript Callback Scope (and in response to numerous other questions on SO - it's a common point of confusion for those new to JS). You just need to wrap the call to the object member in a closure that preserves access to the context object.
You can do it converting by the constructor to a string using .toString() :
function getObjectClass(obj){
if (typeof obj != "object" || obj === null) return false;
else return /(\w+)\(/.exec(obj.constructor.toString())[1];}
You might be able to achieve your goal by using it in a function, and then examining the function's source with toString():
var whatsMyName;
// Just do something with the whatsMyName variable, no matter what
function func() {var v = whatsMyName;}
// Now that we're using whatsMyName in a function, we could get the source code of the function as a string:
var source = func.toString();
// Then extract the variable name from the function source:
var result = /var v = (.[^;]*)/.exec(source);
alert(result[1]); // Should alert 'whatsMyName';
If you don't want to use a function constructor like in Brian's answer you can use Object.create() instead:-
var myVar = {
count: 0
}
myVar.init = function(n) {
this.count = n
this.newDiv()
}
myVar.newDiv = function() {
var newDiv = document.createElement("div")
var contents = document.createTextNode("Click me!")
var func = myVar.func(this)
newDiv.addEventListener ?
newDiv.addEventListener('click', func, false) :
newDiv.attachEvent('onclick', func)
newDiv.appendChild(contents)
document.getElementsByTagName("body")[0].appendChild(newDiv)
}
myVar.func = function (thys) {
return function() {
thys.clickme()
}
}
myVar.clickme = function () {
this.count += 1
alert(this.count)
}
myVar.init(2)
var myVar1 = Object.create(myVar)
myVar1.init(55)
var myVar2 = Object.create(myVar)
myVar2.init(150)
// etc
Strangely, I couldn't get the above to work using newDiv.onClick, but it works with newDiv.addEventListener / newDiv.attachEvent.
Since Object.create is newish, include the following code from Douglas Crockford for older browsers, including IE8.
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o
return new F()
}
}
As a more elementary situation it would be nice IF this had a property that could reference it's referring variable (heads or tails) but unfortunately it only references the instantiation of the new coinSide object.
javascript: /* it would be nice but ... a solution NOT! */
function coinSide(){this.ref=this};
/* can .ref be set so as to identify it's referring variable? (heads or tails) */
heads = new coinSide();
tails = new coinSide();
toss = Math.random()<0.5 ? heads : tails;
alert(toss.ref);
alert(["FF's Gecko engine shows:\n\ntoss.toSource() is ", toss.toSource()])
which always displays
[object Object]
and Firefox's Gecko engine shows:
toss.toSource() is ,#1={ref:#1#}
Of course, in this example, to resolve #1, and hence toss, it's simple enough to test toss==heads and toss==tails. This question, which is really asking if javascript has a call-by-name mechanism, motivates consideration of the counterpart, is there a call-by-value mechanism to determine the ACTUAL value of a variable? The example demonstrates that the "values" of both heads and tails are identical, yet alert(heads==tails) is false.
The self-reference can be coerced as follows:
(avoiding the object space hunt and possible ambiguities as noted in the How to get class object's name as a string in Javascript? solution)
javascript:
function assign(n,v){ eval( n +"="+ v ); eval( n +".ref='"+ n +"'" ) }
function coinSide(){};
assign("heads", "new coinSide()");
assign("tails", "new coinSide()");
toss = Math.random()<0.5 ? heads : tails;
alert(toss.ref);
to display heads or tails.
It is perhaps an anathema to the essence of Javascript's language design, as an interpreted prototyping functional language, to have such capabilities as primitives.
A final consideration:
javascript:
item=new Object(); refName="item"; deferAgain="refName";
alert([deferAgain,eval(deferAgain),eval(eval(deferAgain))].join('\n'));
so, as stipulated ...
javascript:
function bindDIV(objName){
return eval( objName +'=new someObject("'+objName+'")' )
};
function someObject(objName){
this.div="\n<DIV onclick='window.opener."+ /* window.opener - hiccup!! */
objName+
".someFunction()'>clickable DIV</DIV>\n";
this.someFunction=function(){alert(['my variable object name is ',objName])}
};
with(window.open('','test').document){ /* see above hiccup */
write('<html>'+
bindDIV('DIVobj1').div+
bindDIV('DIV2').div+
(alias=bindDIV('multiply')).div+
'an aliased DIV clone'+multiply.div+
'</html>');
close();
};
void (0);
Is there a better way ... ?
"better" as in easier? Easier to program? Easier to understand? Easier as in faster execution? Or is it as in "... and now for something completely different"?
Immediately after the object is instantiatd, you can attach a property, say name, to the object and assign the string value you expect to it:
var myObj = new someClass();
myObj.name="myObj";
document.write(myObj.name);
Alternatively, the assignment can be made inside the codes of the class, i.e.
var someClass = function(P)
{ this.name=P;
// rest of the class definition...
};
var myObj = new someClass("myObj");
document.write(myObj.name);
Some time ago, I used this.
Perhaps you could try:
+function(){
var my_var = function get_this_name(){
alert("I " + this.init());
};
my_var.prototype.init = function(){
return my_var.name;
}
new my_var();
}();
Pop an Alert: "I get_this_name".
This is pretty old, but I ran across this question via Google, so perhaps this solution might be useful to others.
function GetObjectName(myObject){
var objectName=JSON.stringify(myObject).match(/"(.*?)"/)[1];
return objectName;
}
It just uses the browser's JSON parser and regex without cluttering up the DOM or your object too much.

Basic Object/Prototype Syntax Issues

Can someone clear up what I'm doing wrong with my code? I'm a total newb, simply trying to experiment with how to create objects, prototypes, and what the this command refers to in the context of prototypes. However, none of my code is working on jFiddle. I know this code is completely nonsensical, but I'm just trying to find out what the document prints in various cases to get a more concrete grasp of how objects, prototypes, constructors, and the "this" keyword works. But NOTHING is showing up at all!
function Person(identity) {
this.identity = "fellow";
this.logYou = function() {
document.write('hi');
};
};
Person.prototype.logMe = function() {
document.write(this.identity);
};
var Dude = new Person("stud");
Person.logYou();
Person.logMe();
Dude.logMe();
​
function Person() {
this.identity = "fellow";
this.logYou = function() {
document.write('hi');
};
};
When you call this.identity = "fellow"; the this keyword refers the context in which the function is running.
So if you call the function in the Global scope, this refers to window object:
Person();
alert(window.identity); // fellow
And if you instanciate the function, this keyword refers to the new object:
var Dude = new Person();
alert(Dude.identity); // fellow
So the function Person has no property identity.
If you want to have some property for your function:
Person.identity = "fellow";
alert(Person.identity); // fellow
logYou and logMe are methods stored on the prototype of Person so that inheriting objects may have that function to call. You can't call logYou on Person but what you can do is call it on its child, Dude:
Dude.logYou(); // hi
Dude.logMe(); // fellow
These two lines
Person.logYou();
Person.logMe();
throw an error an couse the code to stop executing because logYou and logMe do not exist as properties of Person.
Dude.logMe() and Dude.logYou() will work, printing fellow and hi, respectively.
You cannot call
Person.logYou();
Person.logMe();
as Person has no method logYou or logMe, when you remove these two lines, your code will start working

Method and variable scoping of private and instance variables in JavaScript

I have tried to figure this out or search for it on google, i can only find how to create objects, not exactly how functions work. If someone could explain to me how encapsulation works.
function myObject() {
this.variable1 = "tst";
this.function1 = function() {
//Now this function works. A 'this' function to a private function is ok
_PrivateFunction1();
//Here is error one, I cannot seem to call methods within the object
//from.
this.function2();
}
this.function2 = function() {
alert("look! function2!");
}
function _PrivateFunction1() {
//This does work though. I am confused.
_PrivateFunction2();
}
function _PrivateFunction2() {
alert("look! PrivateFunction1");
//this does not work.
alert(this.variable1);
}
}
I think I can explain this better if we go in reverse order. First, we define some functions:
function _PrivateFunction1() {
//This does work though. I am confused.
_PrivateFunction2();
}
function _PrivateFunction2() {
alert("look! PrivateFunction1");
//this does not work.
alert(this.variable1);
}
This is pretty normal stuff. The only thing that's weird is that they appear inside another function, but that's perfectly fine. JavaScript has function scope, which means that all variables defined inside a function are defined in a new scope. They do not trample on the global namespace. And functions are first-class objects in JavaScript, which means they can be used just like other data types. They can be nested, passed to functions, returned from functions, etc.
Then we run into some trouble:
function _PrivateFunction2() {
alert("look! PrivateFunction1");
//this does not work.
alert(this.variable1);
}
}
Functions in JavaScript are always executed in some context which is referred to by the this keyword. When you call a function directly (i.e. like this: functionName()) the context in which that function executes is the global window object. So, inside _PrivateFunction2, this.variable1 is equivalent to window.variable1 which is probably not what you meant.
You probably wanted to refer to the current instance of myobject which is what this refers to outside of _PrivateFunction2. You can preserve access to this in an inner scope by storing a reference to it in another variable:
var _this = this;
function _PrivateFunction2() {
alert("look! PrivateFunction1");
//this does not work.
alert(_this.variable1);
}
There's something subtle here you should notice. _PrivateFunction2 has access to the variables defined in its lexical scope, which is why it can access _this. This will be important later.
Next up:
function _PrivateFunction1() {
//This does work though. I am confused.
_PrivateFunction2();
}
This should be the most normal-looking section to you, I would think. There's nothing strange going on here. Just one regular function calling another one. Don't be confused by the fact that these are nested inside myObject. That changes the scope they're in, but not much else.
Next we define some instance variables and methods:
this.variable1 = "tst";
this.function1 = function() {
//Now this function works. A 'this' function to a private function is ok
_PrivateFunction1();
//Here is error one, I cannot seem to call methods within the object
//from.
this.function2();
}
this.function2 = function() {
alert("look! function2!");
}
Here this really does refer to myObject, assuming -- and it's an important assumption -- that myObject was called with the new operator, like this:
var obj = new myObject();
If it had been called like this:
var obj = myObject();
Then this would refer to the window object, just like it did for the functions we saw earlier. The key takeaway is that the value of this is not fixed. It's determined by the way in which the function is called. There are even ways to set it to an arbitrary object explicitly.
The value of this inside this.function1 will also be the current instance of myObject, because it will most likely be used like this:
var obj = new myObject();
obj.function1();
Writing object.method() sets this to object inside method.
So how is this.function1 able to call _PrivateFunction1()? Just as we saw earlier when saving the value of this for use inside a nested function, _PrivateFunction1() is just another object defined in this.function1's lexical scope, so it is available for its use, just as _this was earlier.
And it's because of closure that these private variables are still alive long after myObject has returned.
Footnote: Because failing to use new when instantiating objects breaks things so spectacularly without warning, it's considered good practice to capitalize the names of functions you intend to be used as a constructor. So myObject should really be MyObject.
You have to save a copy of the actual object like here note the var that = this
Tested in chrome and FF
for encapsulation I would prefer module pattern like
var someMethod = function(){
var i,
length,
// public method
public = function(num1, num2){
return num1+num2;
},
//private method
_private = function(){};
//exposing the public method
return{
public:public
}
};
var callPublic = someMethod();
callPublic.public(20, 30);// call the public method and return 50
now , if you try to call that private method like
callPublic._private();//it will return not a function since its not been exposed
There are lot of other pattern to encapsulate your methods but module pattern is most common. Hope ot will help you how to encapsulate data in javascript.

Categories