Issue with calling javascript objects - javascript

I'm fairly new to javascript objects and I could use some clarification on calling variables. I'm trying to call the test variable in the bar function. Is this possible? If so how would I do it correctly?
var foo = {
bar: function()
{
var test = 'Hello World';
},
speak: function()
{
// Log the Variable from above ^^
console.log(foo.bar.test);
}
};
Thanks

No; local variables are not visible outside their declaring functions.
Instead, you need to add a property to the object:
foo.test = ...;
You could also set foo.bar.test; that would add a property to the function object.

When you declare a local variable inside the function, you add it to the VariableEnvironment of the functions (which essentially has no difference from the outer LexicalEnvironment, but the ECMA distinguishes them). The function has a reference to the LexicalEnvironment of the scope in which it was declared (in our case, the global object or window). When you try to reference the variable from inside the function, the engine first searches for it the the native VariableEnvironment of the function, and then, if not found, in the outer LexicalEnvironment. In your case, you try to reference a variable from outside of the function, so the engine searches for it in the scope of global object at the very start.
So, to accomplish your task, you should either declare the variable in the outer scrope, and then assign it inside the function, or you should add a new property to the object and then reference it:
var foo = {
test: 'Hello world',
speak: function()
{
console.log(this.test);
}
};

You can access test by return it on call of bar method.
var foo = {
bar: function()
{
var test = 'Hello World';
return test;
},
speak: function()
{
// Log the Variable from above ^^
console.log(foo.bar());
}
};

In order to access the variable test in that manner, you need to define it as a property of the object like so:
var foo = {
test: 'Hello World, before calling bar()',
bar: function()
{
this.test = 'Hello World';
},
speak: function()
{
// Log the Variable from above ^^
console.log(this.test);
}
};
console.log(foo.test);
I also changed the functions to access the object foo using the keyword this. It will usually work but keeping track of your scope in javascript can be tricky sometimes, so just try to be aware of that.

Related

`this` inside inner functions [duplicate]

I have a question concerning how the "this" pointer is treated in a nested function scenario.
Say I insert this following sample code into a web page. I get an error when I call the nested function "doSomeEffects()". I checked in Firebug and it indicates that when I am in that nested function, the "this" pointer is actually pointing to the global "window" object - which I did not expect. I must not be understanding something correctly because I thought since I declared the nested function within a function of the object, it should have "local" scope in relation to the function (i.e. the "this" pointer would be referring to the object itself like how it is in my first "if" statement).
Any pointers (no pun intended) would be appreciated.
var std_obj = {
options : { rows: 0, cols: 0 },
activeEffect : "none",
displayMe : function() {
// the 'this' pointer is referring to the std_obj
if (this.activeEffect=="fade") { }
var doSomeEffects = function() {
// the 'this' pointer is referring to the window obj, why?
if (this.activeEffect=="fade") { }
}
doSomeEffects();
}
};
std_obj.displayMe();
In JavaScript the this object is really based on how you make your function calls.
In general there are three ways to setup the this object:
someThing.someFunction(arg1, arg2, argN)
someFunction.call(someThing, arg1, arg2, argN)
someFunction.apply(someThing, [arg1, arg2, argN])
In all of the above examples the this object will be someThing.
Calling a function without a leading parent object will generally get you the global object which in most browsers means the window object.
Since this appears to be among the most upvoted questions of its kind, let me add, after all these years, the ES6 solution using arrow functions:
var std_obj = {
...
displayMe() {
...
var doSomeEffects = () => {
^^^^^^^ ARROW FUNCTION
// In an arrow function, the 'this' pointer is interpreted lexically,
// so it will refer to the object as desired.
if (this.activeEffect=="fade") { }
};
...
}
};
this is not part of the closure scope, it can be thought of as an additional parameter to the function that is bound at the call site. If the method is not called as a method then the global object is passed as this. In the browser, the global object is identical to window. For example, consider the following funciton,
function someFunction() {
}
and the following object,
var obj = { someFunction: someFunction };
If you call the function using method syntax such as,
obj.someFunciton();
then this is bound to obj.
If you call someFunction() directly, such as,
someFunction();
then this is bound to the global object, that is window.
The most common work around is to capture this into the closure such as,
displayMe : function() {
// the 'this' pointer is referring to the std_obj
if (this.activeEffect=="fade") { }
var that = this;
var doSomeEffects = function() {
// the 'this' pointer is referring to global
// that, however, refers to the outscope this
if (that.activeEffect=="fade") { }
}
doSomeEffects();
}
To understand this question , try to get the output for the following snippet
var myObject = {
foo: "bar",
func: function() {
var self = this;
console.log("outer func: this.foo = " + this.foo);
console.log("outer func: self.foo = " + self.foo);
(function() {
console.log("inner func: this.foo = " + this.foo);
console.log("inner func: self.foo = " + self.foo);
}());
}
};
myObject.func();
The above code will output the following to the console:
outer func: this.foo = bar
outer func: self.foo = bar
inner func: this.foo = undefined
inner func: self.foo = bar
In the outer function, both this and self refer to myObject and therefore both can properly reference and access foo.
In the inner function, though, this no longer refers to myObject. As a result, this.foo is undefined in the inner function, whereas the reference to the local variable self remains in scope and is accessible there. (Prior to ECMA 5, this in the inner function would refer to the global window object; whereas, as of ECMA 5, this in the inner function would be undefined.)
There's a difference between enclosure variables and "this". "this" is actually defined by the invoker of the function, while explicit variables remain intact inside the function declaration block known as the enclosure. See the example below:
function myFirstObject(){
var _this = this;
this.name = "myFirstObject";
this.getName = function(){
console.log("_this.name = " + _this.name + " this.name = " + this.name);
}
}
function mySecondObject(){
var _this = this;
this.name = "mySecondObject";
var firstObject = new myFirstObject();
this.getName = firstObject.getName
}
var secondObject = new mySecondObject();
secondObject.getName();
you can try it out here:
http://jsfiddle.net/kSTBy/
What's happening in your function is "doSomeEffects()", is being called explicitly, this means context or the "this" of the function is the window. if "doSomeEffects" was a prototype method e.g. this.doSomeEffects on say "myObject", then myObject.doSomeEffects() would cause "this" to be "myObject".
As explained by Kyle, you could use call or apply to specify this within the function:
Here is that concept applied to your code:
var std_obj = {
options: {
rows: 0,
cols: 0
},
activeEffect: "none",
displayMe: function() {
// the 'this' pointer is referring to the std_obj
if (this.activeEffect == "fade") {}
var doSomeEffects = function() {
// the 'this' pointer is referring to the window obj, why?
if (this.activeEffect == "fade") {}
}
doSomeEffects.apply(this,[]);
}
};
std_obj.displayMe();
JsFiddle
Since it wasn't mentioned I will mention that using .bind() is a solution -
doSomeEffects=doSomeEffect.bind(this);
doSomeEffects();
}
};
std_obj.displayMe();
Here is a more simple example -
bad = {
name:'NAME',
z : function() {
function x() { console.log(this.name); };
x()
}
};
bad.z() // prints 'undefined'
good = {
name:'NAME',
z : function() {
function x() { console.log(this.name); };
x=x.bind(this);
x();
}
};
good.z() // prints 'NAME'
It is true that using an arrow function => looks slicker and is easy for the programmer. However, it should be kept in mind that a lexical scope is likely to require more work in terms of processing and memory to setup and maintain that lexical scope, compared to simply associating a function's this with a pointer via .bind().
Part of the benefit of developing classes in JS was to provide a method to make this more reliably present and available, to pivot away from functional programming and lexical scopes, and thus reduce overhead.
From MDN
Performance considerations
It is unwise to unnecessarily create functions within other functions if closures are not needed for a particular task, as it will negatively affect script performance both in terms of processing speed and memory consumption.
It's because "this" refers to the self object / local function.
var std_obj = {
options : { rows: 0, cols: 0 },
activeEffect : "none",
displayMe : function() {
if (this.activeEffect=="fade") { }
let This = this; // 'this' here is for the std_obj scope. Create a reference to 'this' if you want to use it elsewhere.
var doSomeEffects = function() {
// 'this' here refers to the doSomeEffects scope. If you don't want "this," you can still use "this" of the std_obj scope.
if (This.activeEffect=="fade") { }
}
doSomeEffects();
}
};
std_obj.displayMe();
I also got a warning "Potentially invalid reference access to a class field via this"
class MyListItem {
constructor(labelPrm) {
this._flagActive = false;
this._myLabel = labelPrm;
labelPrm.addEventListener('click', ()=>{ this.onDropdownListsElementClick();}, false);
}
get myLabel() {
return this._myLabel
}
get flagActive(){
return this._flagActive;
}
onDropdownListsElementClick(){console.log("Now'this'refers to the MyListItem itself")}}//end of the class

Javascript nested function losing scope

Can someone explains the scope binding of the following code please
window.name = "window";
object = {
name: "object",
method: function() {
nestedMethod: function() {
console.log(this.name);
}
nestedMethod();
}
}
object.method(); // print 'window'
I think my question is more about this...why is this losing the scope and default to the global scope ? do all the anonymous functions that we created will go on the global scope ?
Whenever you call a function, simply by writing func(), this inside the function will point to the global object. In your case you write:
nestedMethod();
So this inside nestedMethod is the window object. You can use call (or apply) to manually define a context for you function call:
nestedMethod.call(this);
Any function that's invoked like this:
someFunction();
will have the global scope as the value of this (in non-strict mode). You can either stash the outer scope in a local variable, or else use .call() or .apply():
nestedMethod.call(this);
window.name = "window";
object = {
name: "object",
method: function () {
var self = this;
var nestedMethod = function () {
console.log(self.name); // or object.name without declaring self
}
nestedMethod();
}
}
object.method(); // print 'object'
Save the scope of the object - or use the object itself!
do all the anonymous functions that we created will go on the global scope ?
No, not all the anonymous functions lose their scope, all the functions scopes are bound to the global object(if they are not called with specific this, see apply and call, see the example below)!
window.name = "window";
object = {
name: "object",
method: function () {
var nestedMethod = function () {
console.log(this.name);
}
nestedMethod.call(this); //change the this arg in the current object scope
// when you call this function with .call(this) you are changing the value of the nestedMethod's this to the current this, which is object
}
}
object.method(); // print 'object'
you should declare nested function like this:
Super.prototype.someFunc = function() {
this.nestedFunc = function() {}
//now call it
this.nestedFunc()
}

OOP. Calling methods from within methods

How do I call class methods from functions within the class? My code is:
var myExtension = {
init: function() {
// Call onPageLoad
},
onPageLoad: function() {
// Do something
},
}
I've tried ...
onPageLoad();
... from within the init method but it's saying it's not defined.
I'm not having much luck with google because I don't understand the syntax used. All the JS OOP examples I find online are in a different format. I'm using the format Mozilla use for extension development.
The object the current method was invoked on is available via the special variable this. Any time you call a method on an object, this will refer, within the method, to the object.
var myExtension = {
init: function() {
this.onPageLoad();
},
onPageLoad: function() {
// Do something
},
};
this always refers to the calling object rather than the object the function is defined on or is a property of.
value = 'global';
var ob0 = {
value: 'foo',
val: function() {
return this.value;
},
},
ob1 = {value: 'bar'},
ob2 = {value: 'baz'};
ob0.val(); // 'foo'
ob1.val = ob0.foo;
ob1.val(); // 'bar'
ob0.val.call(ob2); // 'baz'
var val = ob0.val;
val(); // 'global'
In the last case, val is executed as a free function (a function that isn't bound to an object, i.e. not a method), in which case this takes on the value of the global object (which is window in web browsers) within the execution of val. Global variables are actually properties of the global object, hence val() returns 'global' (the value of the global variable named value). Since global variables are actually properties of the global object, you can view free functions as actually being methods of the global object. From this viewpoint, the last two lines (when executed in global scope) are equivalent to:
window.val = ob0.val;
window.val();
This viewpoint doesn't exactly match the reality of scoping, though you'll only notice the difference within functions. In a function, window.val = ... will create a global while var val won't.
value = 'global';
var ob0 = {
value: 'foo',
val: function() {
return this.value;
},
};
function lcl() {
var val = ob0.val; // doesn't set a global named `val`
return val(); // 'global'
}
lcl(); // 'global'
val(); // error; nothing named 'val'
function glbl() {
window.val = ob0.val; // sets a global named `val`
return window.val(); // 'global'
}
glbl(); // 'global'
val(); // 'global'
See MDN's reference page for more on the call method used above. For more on the this variable, see "JavaScript “this” keyword" and "How does “this” keyword work within a JavaScript object literal?"
Assuming that you have called init like this:
myExtension.init();
then it should be:
init: function() {
// before
this.onPageLoad();
// after
}
But in Javascript functions are not actually bound to objects and you can call any function on any other object, like this:
myExtension.init.call(anotherObject); // or
myExtension.init.apply(anotherObject);
In this example this within init would be anotherObject, which doesn't have onPageLoad defined. If you want to support this kind of usage you'll have to manually reference the initial object:
init: function() {
// before
myExtension.onPageLoad();
// after
}
In Javascript you need to explicitly mention the this
this.onPageLoad()
The same is also true for other member variables (remember that in Javascript methods are just member variables that happen to be functions)
this.memberVariable
Have you considered a closure, instead?
For example:
var myExtension = ( function() {
var me = {};
var private_thingy = "abcDEFG123";
var onPageLoad = function() {
// do page loading business
alert( private_thingy );
}
me.onPageLoad = onPageLoad;
var init = function() {
onPageLoad();
}
me.init = init;
return me;
})();
///////////////
myExtension.private_thingy = "DIDDLED!";
// will NOT modify the private_thingy declared within the closure
myExtension.init(); // will work fine.
Anything you define within the closure is available within the closure at all times, and when implemented carefully will yield private members not accessible to users of the object. Only members that you explicitly export - e.g., the me.xxx = xxx lines - are publicly available.
Thus, when onPageLoad executes, "abcDEFG123" will be displayed in the alert, not "DIDDLED!". Users of the object can modify properties using the dot operator until the cows come home; what's not made public by the closure, however, can never be modified: even if the user reassigns a function on the public interface, calls to the private function from within the closure will always point to the function defined within the closure.
The important part: it unties you from the constant use of this (unless you really want to use it; save your fingers for more important typing!).
Give it a shot. And have a look at Javascript: The Good Parts by Crockford.

how to access variables within the Objects

I'm creating an object with multiple functions.. i.e.:
var test = {
setA: function(){
console.log(a)
}
endB: function(){
console.log(a)
}
}
How do I declare variable a so that it can only be accessed in the test object and every function within that the object? and is there anything unique about accessing it than other variables?
I know I can declare a global variable but would rather avoid doing that.
var test = (function() {
var a = 'test';
return {
setA: function(){ console.log(a) }, // <-- was missing a comma
endB: function(){ console.log(a) }
};
})();
This places a in a function invocation which creates a new variable environment. Only function inside this environment will be able to access it.
Your object that contains the functions is returned from the function, and assigned to test. Those two functions will continue to have access to a.
Example: http://jsfiddle.net/yWdFw/
This pattern:
(function() {
// your code
})();
...is commonly called an immediately invoked function expression or IIFE. You're defining a function, and invoking it immediately. As such, its return value is what's being assigned to test.
An alternative to patrick's answer is adding an attribute to the object and then accessing it via this
var test = {
a: 'blah',
setA: function(){
console.log(this.a)
},
endB: function(){
console.log(this.a)
}
}

When returning an object from a JavaScript constructor function (avoiding 'new') how do I implement public members?

I have begun writing my 'class' type JavaScript functions like the Module Pattern or Revealing Module patten. This avoids the use of 'new' and allows me to define which functions are public in a single place. However, I have been unable to see how to use and access public data members in this pattern.
e.g. the member 'id' below is accessible through myobj.getId(), but myobj.id is undefined.
function setup(){
var myobj = MyObject();
myobj.initialize();
alert(myobj.getId()); // returns 3, as expected
alert(myobj.id); // returns undefined
}
function MyObject(){
var id;
function initialize(){
//do some stuff that initializes data including...
id = 3;
}
return{
initialize:initialize,
id:id,
getId:function(){ return id;}
}
}
Is there no way to get myobj.id to work returning the value that was set in initialize()?
Your problem is that you aren't taking advantage of closure. The line id:id creates a new variable as a member of the object literal you are returning. This has the default value undefined. Then you are assigning the same variable id back to itself, undefined again.
Also, a module is a single object instance, not a factory function. Try something like this:
var myModule = (function(opts) {
var foo = opts.foo || 0, //private variables with default values
bar = opts.bar || 0, // if none are passed in
product = function() { //private method
return (foo * bar);
};
return {
getFoo : function() { //public methods
return foo;
},
fooTimesBar : function() {
return product();
}
}
})({
foo : 5, //options object
bar : 7
});
The core of the module pattern is a self executing anonymous function that declares variables and then returns an object that has privileged access to those variables through closure.
The extra parens at the end, here containing an object literal with some options that get passed in, executes the function, which then returns an object and assigns it to myModule.
Anything declared as a member of that returned object can be accessed publicly. Code in the returned object has access to the variables defined in the anonymous function through closure even after the function has returned. The variables declared in the anonymous function are effectively private. Code outside the function cannot address them except through the methods provided in the returned object.
The whole thing results in a single object instance in myObject. No more than one can be created, which is the definition of a module. A similar approach could be taken the create a factory function however.
The reason is that your variable id is set to undefined by default and it's type will be undefined as well. Now, because undefined type is a primitive one your assignment in the returned object will be a value assignment, not reference. So obj.id will become undefined in the instance and not the same as the id variable in the constructor function.
Now initialize will change the id in the constructor function, and getId will return the same id, but obj.id will refer to the undefined object property.
function MyObject(){
// initialize is used as a public function so
// this will always refer to the current instance
function initialize(){
this.id = 3;
}
return {
// no need to define id here it will
// report undefined on access by default
initialize: initialize,
getId:function(){ return this.id; }
}
}
Run the whole stuff to see it works as expected.
​
You can solve this and still maintain the syntactic sugar of the Revealing module pattern by returning a cached object instead of an anonymous one.
eg:
NAMESPACE.Module = (function () {
//All public members go on api
var api = {}
api.id = 3;
//Private members
var self,
foo,
bar;
/**
#public
*/
api.init = function () {
self = this;
console.log(this); //NAMESPACE.Module
}
/**
#private
*/
function _privateFunction() {
console.log(self); //NAMESPACE.Module
}
return api;
}());

Categories