Scope issue inside objects that are inside objects - javascript

I've come across a problem while trying to build a simple jQuery plugin, having to do with scopes I guess.
The problem in short: A class (A) creates an object (B), in which a property (C) is set to one of the class methods (D). How can I access class A's methods not contained inside the object (B) through the property ( C)?
Longer version (code below): I'm declaring an object (lets call it publicMethods) inside the plugin, comprised of a bunch of methods. These methods should be some default methods (declared inside the plugin), or user declared ones if the user has declared her own when initializing the plugin.
The idea is that when the user defines her own custom method, there should be some functions and variables accessible to her (like this.someVar) in that function.
This creates some limitations though.
I want the default methods to have access to some internal functions and variables, not contained inside the object publicMethods. But when I access these methods through the object they are inside, instead of calling them directly, I do not have access to another variables/functions not inside that object.
I'm trying to find a way to let the default methods have access to it's class siblings. I know I can do some conditional statements before calling the method (if it is user defined or not), or even declare a global variable pointing to "this", but I'd rather keep it clean.
var Plugin = function (opt) {
this.settings = $.extend({
"someVar" : "Value",
"someFunc" : null
});
this.anotherVar = "Hello World";
this.setPublic();
this.run();
}
Plugin.prototype = {
setPublic: function() {
this.publicMethods.someFunc = this.someFunc;
if ($.isFunction(this.settings.someFunc)) {
this.publicMethods.someFunc = this.settings.someFunc;
} else {
this.publicMethods.someFunc = this.someFunc;
}
},
someFunc: function(arg) {
return this.anotherVar; // returns type error the second time
},
run: function () {
this.someFunc();
this.publicMethods.someFunc();
}
}

From MDN: Function.prototype.bind():
The bind() method creates a new function that, when called, has its this keyword set to the provided value, [...].
So the following should work:
setPublic: function() {
this.publicMethods.someFunc = this.someFunc.bind(this);
if ($.isFunction(this.settings.someFunc)) {
this.publicMethods.someFunc = this.settings.someFunc.bind(this);
}
// This is redundant anyway:
/* else {
this.publicMethods.someFunc = this.someFunc.bind(this);
}*/
},

Related

I want access of a property of my class in a static metod, how can i do? is it possible? [duplicate]

I have a code like that:
User = function(){}
User.a = function(){
return "try";
}
User.b = function(){
}
​
From User.b() I can call User.a() using:
User.b = function(){
return User.a();
}
but not using this since it's not an instance of user (User.a() and User.b() are something like "static methods").
What i want to do is to be able to call User.a() from User.b() without knowing which is the main function, in this case User.
Something like this to be used in static methods.
In reality there is no methods or static methods in js, there's just functions that are assigned to object properties (functions being objects as well) and they all work the same way. Since you are calling it like User.b(), this will be User for the call.
User.b = function() {
return this.a();
}
The only thing that determines the context of the function is how you call it.
If you call it using a plain identifier (a function name, a variable or a property), the context will be the global window object:
someFunction();
If you call it using a period to access an object member, the context will be the object:
someObject.someFunction();
If you copy a member from an object to a variable, there is no connection to the object any more, and it will be called with window as context:
var x = someObject.someFunction;
x();
If you assign a function as a property to an object, and call it using the object, the context will be the object:
someObject.x = someFunction;
someObject.x();
For your specific case, User is a function, which also is an object.
If you call the function using User.b, its context will be the User object, which happens to be a function in this case. From within the function you can still use this to access the context:
User.b = function(){
return this.a();
}
You don't have normal inheritance in javascript. I guess you are trying to do something like this:
User = function(){
this.a= function(){
return 'try';
}
this.b= function(){
return this.a();
}
}
This way User becomes a constructor. Each new instance of User will have acces to these methods. So if you want to create a new instance of the User class, you can use the new keyword:
var client= new User()
and then you'll have access to all the methods from user using client
client.b() //returns 'try'
Well, functions exist independently of their container objects; they're just values. So if you're not calling them as methods on an object, they inherit whatever this is in the calling context. In that case, expecting them to know about their container would be the same as assigning User.x the value 1 and then expecting the number 1 to somehow know about User.
However, when you call User.a() or User.b(), you are in fact calling them as methods - methods of the (function object) User. So this will be the same as User, and b can just call this.a() and you should be good to go.

Get method's instance owner

Given a class and an instance of it
var class=function() {
this.propA=99;
this.methodA=function() {
console.log(this.propA);
};
};
var object=new Class();
I'd like to be able to perform a call to methodA where this will be the instance of it and the example (this.propA) will work. Exactly as
object.methodA.call(object);
but without having any reference to object. Like this in some pseoducode:
var methodToCall=object.methodA;
...
...
methodToCall.call(getInstanceOwnerOf(methodToCall));
The objective of this is to pass methods as callbacks to async functions and keep this as the instance when the method is called.
Some workarounds would be to pass method and object to that async function, or to store this in a local variable, but these are the things I want to avoid.
Use bind to bind to the context you want function called in. Note this returns a NEW function which is not the same as the original.
I usually create the new function and give it a different name but you can do it multiple ways.
To be more specific, you can't be sure this is the class the function is declared in, depends on how you called the function and if you are in strict mode.
an example below:
Fiddle: https://jsfiddle.net/f7af535L/
class SomeClass {
constructor(someVar) {
this.myVar = someVar;
this.publicSayVar = this.sayVar.bind(this);
}
sayVar() {
console.log(this.myVar);
}
}
var object = new SomeClass("hello");
var testcall = object.publicSayVar;
testcall();

Issue related to declaring Variable in Famo.Us

I have Small application in Famo.us Framewok.
I want to declare array variable that can be use in calling js.
I have 2 .js file: (1) PageView.js (2) GetContent.js
(1) PageView.js
function AddContent() {
View.apply(this, arguments);
var getContent = new GetContent();
getContent.AddPages();
(2)GetContent.js
function GetContent() {
View.apply(this, arguments);
}
GetContent.prototype = Object.create(View.prototype);
GetContent.prototype.constructor = GetContent;
GetContent.DEFAULT_OPTIONS = {};
GetContent.prototype.AddPages = function () {
GetData();
}
I want to declare array variable in GetContent.js file that can be accessible in PageView.js using the object of GetContent defiened in PageView.js in above code.
so that i can use like getContent.variablename[1]
how to achieve it?
Your GetContent class would need to have an array assigned to it's instance like so:
this.variablename[1, 2, 3];
Adding this allows your array to be attached to the class's specific instance. Otherwise, your array will only exist for the lifetime of the function scope you create it in.
You may also find that you can't access the getContent object after it's been created in your PageView for the same reason. Instead try this.getContent = new GetContent();
Lastly, try to avoid directly accessing other class's variables directly. Instead, use getter/setter methods which allow the class to share and modify their data securely.

Scope private classes in a separate file

Is there a way to create a private class in a separate file without polluting the global namespace? Currently I just create a sub-namespace and put all of the private classes that other public classes need to function, but is there a way to just make a class altogether private, yet in another file?
You are probably looking for the "Module Pattern" in JavaScript. The Module Pattern name can refer to a lot of different patterns but the basic concept to to declare functions and attributes that are only available to a function which has already been called. Like this:
myModule = function () {
var me = {},
iAmPrivate = 1;
function privateFunc() {
// stuff can access iAmPrivate and iamPublic
}
me.iamPublic = 1;
me.publicFunc = function () {
// stuff can access iAmPrivate and iamPublic
};
return me;
}());
myModule.publicFunc(); // this can be called
myModule.iamPublic; // this can be accessed
myModule.iAmPrivate // xx can't do this
myModule.privateFunc() // or this
Because of how closures and scope works, Items declared local to that function call are available to all functions declared in that function call but nothing outside of the function call. The function has been called so they can never be accessed.
You can read a lot more about it here : http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html, and of course with a Google search now that you know what it is called.

Examples of multiple instance javascript widgets (on same page)?

Apologies for the quick question, but I'd like to see some sample widgets that allow multiple instances in the same page. (Articles about this technique would also be good!)
Digg's widget allows this (http://about.digg.com/downloads/widgets) but I don't know of any others.
Do you?
Thanks.
See any of the YUI widgets. Eg multiple YUI-enhanced buttons on a page.
Creating multiple instances with per-instance data
The basic technique is shown below.
Since the calling program uses new, a new instance of the Larry.widget object is created for each widget. So each widget has its own, separate object "this" and uses it for storing per-instance data.
At the same time, the object's prototype holds the functions. So all of the widgets share the same functions, but have their set of data.
Larry = {}; // Create global var
Larry.widget = function (options) {
// create with new. Eg foo = new Larry.widget({an_option: true, id: "q_el"});
// options: object with members:
// an_option
// id
// Then call foo.xyz(); to get the widget to do xyz
this.init(options);
};
Larry.widget.prototype = {
constructor: Larry.widget,
// Setting the constructor explicitly since we're setting the entire
// prototype object.
// See http://stackoverflow.com/questions/541204/prototype-and-constructor-object-properties/541268#541268
init: function(options) {
this.id = options.id;
this.an_option= options.an_option;
this._function_a(); // finish initialization via a function.
}, // remember that function init is a member of the object, so separate
// the functions using commas
_function_a: function() {
// This is a "private" function since it starts with _
// Has access to "this" and its members (functions and vars)
....
},
xyz: function() {
// This is a "public" function.
// Has access to "this" and its members (functions and vars)
...
} // Note: NO TRAILING COMMA!
// IE will choke if you include the trailing comma.
}

Categories