I wrote some javascript to simulate a namespace. The following global allows me to access the get_cp_span() getter method from other namespaces:
var my_ns; // global access
$(document).ready(function() {
my_ns = new my_namespace(); // need global access to my_ns
});
function my_namespace() {
var cp_span = $("#cp_span");
// public getter
this.get_cp_span = function() {
return cp_span;
}
var do_something = function() {
//get_cp_span().hide(); // ReferenceError: get_cp_span is not defined
//this.get_cp_span().hide(); // TypeError: this.get_cp_span is not a function
my_ns.get_cp_span().hide(); // works
}
};
I thought that I would be able to easily access my public getter cp_span() from within the my_namespace() by calling this.get_cp_span() or by just calling get_cp_span() but it only works when I call my_ns.get_cp_span() which is how I would call it from a different 'namespace'.
In order for me to access get_cp_span() from within the same function, I have to refer to the global variable.
new creates a plain object, inside my_namespace this points to the newly created object, you can save this object inside another private variable so that any function declared inside my_namespace have access to it, I've seen that this variable is commonly named as self or me but you can name it whatever you want
var my_ns; // global access
$(document).ready(function() {
my_ns = new my_namespace(); // need global access to my_ns
});
function my_namespace() {
// save the newly created object
var me = this;
var cp_span = $("#cp_span");
// public getter
this.**get_cp_span** = function() {
return cp_span;
}
var do_something = function() {
me.get_cp_span().hide();
}
};
Note that if you call my_namespace multiple times, me will refer to each instance created, I'd avoid using new though since I think that the namespace should be unique right? I'd be better to use the singleton pattern
Related
Hello I'm having a problem that haven't searched before
I'm trying to recode my javascript used for accessing google api's so that I can create objects to access them in further projects .
Let me Explain the Code because I'm not posting the original code here below code is the just like an example of my code
I'm a having constructor function and it has arrays declared with 'this' keyword. and Then I have an prototype of the constructor function and inside that prototype I had a nameless function created to access jquery requested output from a server.But I'm unable to access those array objects
function cons(){
this.objectarray = [];
}
cons.prototype.profun = function(){
this.objectarray[0] = 'working';
alert(this.objectarray[0]);//Access is possible
$.get('requesting url',{'parameters'},function(data){
alert(this.objectarray[0]);//Access is not possible
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
when I try to access the object inside that jquery function I'm getting this error from browser console
TypeError: this.YouTubeTitle is undefined
You have to cache the this object so that when you use the this keyword in your callback, it refers to the correct object:
function cons(){
this.objectarray = [];
}
cons.prototype.profun = function(){
// this is volatile in JavaScript. It's meaning changes depending
// on the invocation context of the code that contains it. Here,
// this will refer to your "cons" object instance.
var self = this;
this.objectarray[0] = 'working';
alert(this.objectarray[0]);
$.get('requesting url','parameters',function(data){
// But here, "this" will be bound to the AJAX object
alert(self.objectarray[0]); // <-- Use cached this object
});
};
//*************************
var c = new cons();
c.profun();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Inside the GET-Callback there is a local this which overrides your Prototype-Function's this. Store the outer this in a named variable and call that inside the callback and you will be fine.
let outerThis = this;
somethingWithCallback(function(){
alert(outerThis);
})
I've found solution for this from one of the comments
the below code is the solution
function cons(){
this.objectarray = [];
}
cons.prototype.profun = function(){
this.objectarray[0] = 'working';
alert(this.objectarray[0]);
$.get('requesting url',{'parameters'},function(data){
alert(this.objectarray[0]);
}.bind(this));//by binding 'this' we can access the 'objectarray'
}
Thanks for the solution #Redu from comments
You can wrap your anonymous function with $.proxy to persist the outer this context.
function cons() {
this.objectarray = [];
}
cons.prototype.profun = function() {
this.objectarray[0] = 'working';
alert(this.objectarray[0]);
$.get('requesting url', {
'parameters'
}, $.proxy(function(data) {
alert(this.objectarray[0]);
}, this));
}
I have an object in Javascript and want to process the data passed into the constructor using a function that could later be called externally with more data. Naturally I don't want to duplicate the code (once in the constructor, once in a function), so how should I best set this up?
I could use a nested function, but I'm told this is inefficient:
function MyOb(data) {
this.myData = {};
function addData(newData) {
//Add newData to myData
}
addData(data);
}
But if I use a prototype I get a "can't find variable addData" error on line 3:
function MyOb(data) {
this.myData = {};
addData(data);
}
MyOb.prototype.addData = function(newData) {
//Add newData to myData
}
So am I forced to either use a nested function or repeat myself, or is there a way of making this work using prototype?
Change
function MyOb(data) {
var myData;
addData(data);
}
to
function MyOb(data) {
this.myData = {}; // or another initialization
this.addData(data);
}
You need the explicit this in JavaScript objects.
Note also that using var myData makes it private : you won't be able to use this variable from functions defined outside the constructor, including the addData function. That's why you probably need this.myData instead.
Using the prototype you need to create a new object:
var abc = new MyOb(data);
then you can access the function using the this:
function MyOb(data) {
var _myData; // local variable in this scope (addData won't have access)
this.myData = {}; // public variable
this.addData(data);
}
If you don't use the newto build your object, then the thiswill be the window, and your code won't work
You should just make the nested function publically available as a property on your object:
function MyOb(data) {
var myData;
function addData(newData) {
//Add newData to myData
}
addData(data);
this.addData = addData;
}
Your current code with the prototype suffers from the problem that you're trying to get the function like a variable, while it's a (inherited) property of your instance (referenced by this). However, changing it to
this.addData(data);
would lead to the error can't find variable myData in the prototype function - it's a variable that is local to the constructor. You would have to make that a instance property as well to use the prototype. See also Javascript: Do I need to put this.var for every variable in an object?.
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.
i have JavaScript components, that has following architecture:
var MyComponent = function(params)
{
setup(params);
this.doSomething()
{
// doing something
};
function setup(params)
{
// Setup
// Interaction logic
var _this = this; // "this" points to DOMWindow, not to created object
$(".some-element").click(function(){
_this.doSomething(); // it craches here, because of above
});
}
};
When something, being controlled by interaction logic, happens, sometimes i must forward execution to "public" methods of component.
In this situation, i have a problem with "this" pointer.
Sample code demonstrates it:
var Item = function()
{
this.say = function()
{
alert("hello");
};
this.sayInternal = function()
{
_sayInternal();
};
function _sayInternal()
{
this.say();
};
};
To test it,
Create an object:
var o = new Item();
This works fine:
o.say(); // alerts "hello"
This crashes:
o.sayInternal();
I get an error:
TypeError: Result of expression 'this.say' [undefined] is not a function.
I think, such a behaviour takes place, because _sayInternal() function is declared (and not assigned to object, like "this.say = function()"). This way, it is shared across all created objects and acts like a static function in C++.
Is this true ?
No, sayInternal is not shared between created objects. But you are right, the created objects don't have access to sayInternal as it is not assigned to them. This function is only local to the constructor function.
this always refers to the context a function is invoked in. If you call it like func(), then this refers to the global object (which is window in browser). If you set the function as property of an object and call it with obj.func(), then this will refer to obj.
If you assign a "bound" function to a variable and call it:
var method = obj.func;
method();
then this will again refer to the global object. In JavaScript, functions are like any other value, they don't have a special relationship to the object they are assigned to.
You can explicitly set the context with call or apply:
var MyComponent = function(params)
{
setup.call(this, params); // <- using `call`
this.doSomething()
{
// doing something
};
function setup(params)
{
// Setup
// Interaction logic
var _this = this; // "this" to new created object
$(".some-element").click(function(){
_this.doSomething();
});
}
};
or in you other example:
var Item = function()
{
this.say = function()
{
alert("hello");
};
this.sayInternal = function()
{
_sayInternal.call(this);
};
function _sayInternal()
{
this.say();
};
};
That said, this approach to assign functions to objects is not good, because every instance will have its own this.sayInternal function. So for the Item code above, every creation of an instance involves creating three functions too, which is a waste of memory.
Making use of prototype inheritance would be a better way:
var Item = function() {
};
Item.prototype = (function() {
function _sayInternal() {
this.say();
};
return {
say: function() {
alert("hello");
},
sayInternal: function(){
_sayInternal.call(this);
}
}
}());
This way, _sayInternal is only created once and all instances inherit (refer to) the prototype, so say and sayInternal also exist only once. The "trick" with the immediate function makes _sayInternal only accessible by say and sayInternal.
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;
}());