I have an object literal as follows. In the Init method I set a handler for a click event. Later, when the handler is called, I want to access the Bar property using this keyword. At that point, this has the jQuery meaning.
Also, to make things clear, I don't want to implement functions inline with the selectors.
var StackOver = {
Bar: "MyBarValue",
Init: function(){
$("#postId").click(this.Foo);
},
Foo: function(eventObject){
// here **this** is jQuery keyword
// how do I access StackOver.Bar?
}
}
How do I access properties of this object literal inside Foo?
This could have been easy if I was using a constructor literal, which is not a go for me:
var StackOver = function (){
var self = this;
function bar()
{
// I can use self here
}
}
edit I forgot to mention that I use the Revealing Module Pattern in this object literal, that hides private properties from the object.
Everyone else is suggesting .bind, which makes sense, but you also may just be able to reference the object itself in the closure:
Foo: function(eventObject) {
console.log(StackOver.Bar);
}
one option:
Init: function(){
$("#postId").click(this.Foo.bind(this));
}
another option: (from http://api.jquery.com/jquery.proxy/)
Init: function(){
$("#postId").click($.proxy(this.Foo, this));
}
both of there take the this variable so you can't use this for other purposes
if, however, you can't use this:
Init: function(){
$("#postId").click(function (self) {
return function (event) {
return self.Foo(self, event);
}
}(this));
}
and in Foo just add the self parameter.
Foo: function (self, event...) {
...
}
All that said, why can't you use (function () {var self = this; ... }()) ?
It is the revealing module pattern, after all
var StackOver = {
/*...*/
Init: function(){
$("#postId").click(this.Foo.bind(this));
},
/*...*/
Foo: function(eventObject){
// here **this** was actually the html element
// now it's the old this.
alert(this.Bar);
}
}
I'm not sure why this has to be an object literal. If you can use other structures, you could gain access through a revealing module like this:
var StackOver = (function() {
var bar = "MyBarValue",
init = function(){
$("#postId").click(foo);
},
foo = function(eventObject) {
// here `this` might be a jQuery wrapper object
// but you can access `bar` directly.
};
return {
Bar: bar, // Or not. Do you really want this public?
Init: init,
Foo: foo
}
}())
Related
How can I access baz() from inside the bar() function in the following code?
var obj = {
baz : function(){ alert("Hi!"); },
foo: {
bar: function(){
baz();
}
}
}
JavaScript doesn't have kind of a built-in parent reference because an object can be referenced by multiple 'parents' in what we call a many-to-one relationship.
As others have said, in this simplified case, simply calling obj.baz() will work.
In a more complicated case, you would have to manually build the object and track parenthood:
// Create the root object
var rootObject = {baz: function() {console.log('rootBaz');}}
// And the basic child
var childObject = {foo: function() {console.log('childFoo');}}
// Configure the parent
childObject.parent = rootObject;
// Add our call.
childObject.baz = function() {this.parent.baz()};
// Invoke and test
childObject.baz();
Which can be slightly simplified:
var rootObject = {
baz: function() {console.log('rootBaz');}
};
var childObject = {
foo: function() {console.log('childFoo');},
baz: function() {this.parent.baz()}
};
childObject.parent = rootObject;
childObject.baz();
Updated per Sujet's comment
In addition, if you need to make sure that baz has the correct value for this you can use either call or apply.
baz: function() {this.parent.baz.call(this.parent)}
If your code doesn't require this then I would recommend a straight function call per my original answer.
Just use the object reference:
var obj = {
baz : function(){ alert("Hi!"); },
foo: {
bar: function(){
obj.baz();
}
}
}
You need to reference via object.property notation.
In your example you would get baz via:
obj.baz()
Some great resources for this:
http://www.w3schools.com/js/js_objects.asp
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects
What is the best way to solve this scoping problem?
NAMESPACE.myObject = {
foo: 'foo',
init: function() {
$('.myBtn').on('click', this.myMethod);
},
myMethod: function() {
console.log($(this), foo);
}
};
NAMESPACE.myObject.init();
The result of the console.log should be the jQuery object that was clicked and the propertie foo of myObject. How would I achieve this?
Basically you can't have more than one this, so need to work around it.
As a general rule, create a scoped variable (THIS in the example below) to hold the scope you want to retain/access from inside any other scope.
You need to retain the this on the call to the myMethod though, inside the click handler, so you can't just pass myMethod as it loses the myObject instance.
NAMESPACE.myObject = {
this.foo: 'foo',
init: function() {
var THIS = this;
$('.myBtn').on('click', function(){
// "this" here is the button clicked
// "THIS" is still the myObject instance
THIS.myMethod(this);
});
},
myMethod: function(element) {
// "this" here is myObject
// The clicked element was passed as parameter "element" instead
console.log($(element), this.foo);
}
};
NAMESPACE.myObject.init();
I hope I explained this clearly enough :)
As jfriend00 points out, you can also use bind to basically create a function call with this scope on-the-fly (very cute), but that does not work on IE8 or older.
You can use .bind() like this:
NAMESPACE.myObject = {
foo: 'foo',
init: function() {
$('.myBtn').on('click', this.myMethod.bind(this));
},
myMethod: function() {
console.log($(this), foo);
}
};
NAMESPACE.myObject.init();
Or, for older versions of IE, since you already have jQuery you can use jQuery's $.proxy():
NAMESPACE.myObject = {
foo: 'foo',
init: function() {
$('.myBtn').on('click', $.proxy(this.myMethod, this));
},
myMethod: function() {
console.log($(this), foo);
}
};
NAMESPACE.myObject.init();
When you pass this.myMethod to the event listener, it loses its binding to this (as you've noticed) because the event listener doesn't save that reference or call the method with it. One way to keep that binding is to use .bind() (requires IE9 or a polyfill for earlier versions of IE).
Since I see you tagged jQuery, you can also use this approach, I know it is different from what you posted in the question, but I still an option.
working example
var NAMESPACE = NAMESPACE || {};
$(function() {
"use strict"
$.extend(NAMESPACE, true, {
getMyObject: function() {
function myObject() {
var self = this;
self.foo = 'foo';
self.init = function() {
$('.myBtn').click(self.myMethod);
};
self.myMethod = function() {
console.log($(this), self.foo);
};
}
return new myObject();
}
});
var myObject = NAMESPACE.getMyObject();
myObject.init();
})
I have a class-like function
var myapp = function() {
this.method = function() {
//Do something...
}
}
To reference myapp from within methods, the first line in the myapp function is
var self = this;
So a method in myapp can reference the "class" safely
this.anothermethod = function() {
self.method();
}
The full code:
var myapp = function() {
var self = this;
this.dosomething = function(Callback) {
Callback();
}
this.anothermethod = function() {
//Pass a callback ("self" is required here)...
this.dosomething(function() {
self.complete();
)};
}
this.complete = function() {
console.log('All done!');
}
}
My question is: can I assign var self = this; from outside the declaration of myapp? I don't want to set self every single time I write a "class".
Kind of like this:
var library = function() {
this.loadclass = function(Name) {
var tempclass = window[Name];
library[Name] = new tempclass();
library[Name].self = library[Name];
}
}
var myapp = new library();
myapp.loadclass('myapp');
myapp.myapp.dosomething();
It doesn't work as expected. self equals window for some reason.
I know it's a little abnormal programming, but can it be done?
Note about using self: I remember why I started using it. I wanted to reference the base class (this) from within callbacks inside methods. As soon as you try to use this within a function within a method, it then references the method, not the base class.
Unless you are detaching the methods from the object and calling them as plain functions, you don't need a self variable at all. The method can reach its object using the this keyword:
var myapp = function() {
this.method = function() {
//Do something...
}
this.anothermethod = function() {
this.method();
}
}
No, you can't really; not the way you're creating objects at least.
You can sort of do this, by enumerating all the functions on the object and binding them to the object itself. Something like this:
Object.keys(obj)
.filter(function(n) { return typeof obj[n] == "function" })
.forEach(function(n) { obj[n] = obj[n].bind(obj) })
This function will go over the public, enumerable properties of obj and make sure that any functions on it are bound to obj; i.e. this is now bound to obj.
A primer on this
When you call new, this within the constructor gets bound to the newly created object. If you do need a reference to this as it was bound at constructor time, you do need to keep away a reference to it.
Functions in JavaScript are bound to wherever it is called. Here's an example:
var foo = new function() {
this.bar = function() {
return 'bar'
}
this.baz = function() {
return this.bar()
}
}
console.log(foo.bar()) // bar
console.log(foo.baz()) // bar
var bar = function() {
return "window"
}
var baz = foo.baz
console.log(baz()) // window
When we call foo.baz() it'll look to foo for the implementation of bar, but when calling foo.baz through a "detached" reference, it'll look to whatever the global object is (in this case the browser window object) and call bar from there. Because we defined bar in the global context, it then returns window.
The practice of assign a variable called self is so that it doesn't matter how you call your methods, because you always reference the this at the time of creation through the self variable. You don't have to write things this way, but then you should understand that references to this may change under your feet.
I'm trying to create a client-side api for a web control using the Prototype pattern. However I want to make life easier by not having to manage "this".
This is some sample code (i have commented the problematic line):
MyObject = function ()
{
MyObject.initializeBase(this);
this._someProperty = null;
};
MyObject.prototype = {
initialize: function()
{
// Init
},
get_someProperty: function()
{
return this._someProperty;
},
set_someProperty: function(value)
{
this._someProperty = value;
},
doSomething: function ()
{
$('.some-class').each(function ()
{
$(this).click(this.doClick); // this.doClick is wrong
});
},
doClick: function ()
{
alert('Hello World');
}
};
Normally, using the revealing module pattern I would declare a private variable:
var that = this;
Can I do something similar with the Prototype pattern?
You can do the exact same thing you are used to, just do it within the doSomething method:
doSomething: function ()
{
var instance = this;
$('.some-class').each(function ()
{
$(this).click(instance.doClick);
});
},
This approach has nothing to with prototype or not, it's just how to manage context with nested functions. So when a function on a prototype (method) has nested functions within in, you may have to preserve the context this at any of those level if you want to access it in a nested scope.
ES5's Function.prototype.bind() might be an option for you. You could go like
doSomething: function ()
{
$('.some-class').each(function(_, node)
{
$(node).click(this.doClick); // this.doClick is right
}.bind(this));
},
Now, we proxied each event handler by invoking .bind() and as a result, we call it in the context of the prototype object. The caveat here is, you no longer have this referencing the actuall DOM node, so we need to use the passed in arguments from jQuery instead.
I'm always learned to define a function in JavaScript like this:
function myFunction(arg1, arg2) { ... }
However, I was just reading Google's guide to Javascript, it mentioned I should define methods like this:
Foo.prototype.bar = function() { ... };
Question: Is "Foo" in the example an Object, or is it a namespace? Why isn't the Google example the following code (which doesn't work):
prototype.bar = function() { ... };
UPDATE: In case it helps to know, all of my JavaScript will be called by the users browser for my web-application.
Your two examples are not functionally equivalent. The first example simply defines a function (probably a global one, unless you define it inside another function). The second example extends the prototype of a constructor. Think of it as adding a method to the class Foo.
Unless you're building a JavaScript library, my suggestion would be to use neither and use some kind of namespace system. Create a single global object that acts as a namespace through which you can access all your functions.
var MyObject = {
utils: {
someUtil: function() {},
anotherUtil: function() {}
},
animation: {
// A function that animates something?
animate: function(element) {}
}
};
Then:
// Assuming jQuery, but insert whatever library here
$('.someClass').click(function() {
MyObject.animation.animate(this);
});
If you want to emulate classes in JavaScript, you would define the "class" as a function (the function itself being the constructor) and then add methods through the prototype property.
function Foo() {
// This is the constructor--initialize any properties
this.a = 5;
}
// Add methods to the newly defined "class"
Foo.prototype = {
doSomething: function() { /*...*/ },
doSomethingElse: function() { /*...*/ }
};
Then:
var bar = new Foo();
console.log(bar.a); // 5
bar.doSomething();
// etc...
I'm always learned to define a function in JavaScript like this:
function myFunction(arg1, arg2) { ... }
There are two ways to define a function. Either as a function declaration
function foo(...) {
...
}
Or as a function expression
var foo = function() {
...
};
Read more here.
However, I was just reading Google's guide to Javascript, it mentioned I should define methods like this: Foo.prototype.bar = function() { ... };
This is specifically related to method creation for objects, not just normal, stand-alone functions. Assuming you have the base object declaration:
var Foo = function() {
...
};
Just like any other assignment, to assign a function to an object's property, you must use an assignment expression. You can do this two ways. The succinct and common way (as suggested by Google's reference)
Foo.prototype.bar = function() {};
Or, if you want to continue to use the declarative form of defining functions
function bar() {
...
};
Foo.prototype.bar = bar;
This is normally more verbose than necessary, but may be useful in situations where you want to assign the same method to multiple object prototypes.
Question: Is "Foo" in the example an Object, or is it a namespace? Why isn't the Google example the following code (which doesn't work): prototype.bar = function() { ... };
Foo is an object. Although the concept can be expressed through the use of static objects, as I've shown in my answer to your other question, there is no such thing as namespaces in JavaScript. Further, especially in the example code given, Foo is likely intended to be an instantiated object, which precludes it from being behaving like a namespace.
Of course it doesn't work: prototype has not been defined as an object (unless, of course, you define it as such). The prototype property exists on every object (a function is also an object), which is why you can do Foo.prototype.bar = ...;. Read more here.
=====> 2017 Update <=====
This question and answers is 7 years old and is very outdated. This answer includes new syntax for versions of ES5, ES6, and compatible with ES7.
Best way to define a function?
There is no one "Best" way to define a function. How you define the function is dependent on the intended use and lifetime of the function.
Global functions
Defined as a statement with the function token followed by the function name with lowercase camelcase
function functionName (arguments) {
// function body
}
is preferable over the function expression...
var functionName = function (arguments) {
// function body
}
...as the assignment to the variable of the function does not occur until the defining line is executed. Unlike the prefered method which is available immediately after parsing before any code is executed.
const functionName = function(arguments){/*function body*/}
var functionName = function functionName(arguments){/*function body*/}
var functionName = function functionAltName(arguments){/*function body*/}
Function objects
As a function statement with uppercase camelcase function name
function MyObjectFunction (arguments) {
/*function body*/
// if this function is called with the new token
// then it exits with the equivalent return this;
}
const obj = new MyObjectFunction(foo);
Anonymous function expression.
A common practice is to create object via an immediately invoked function that has no name (and is hence anonymous)
;(function (arguments) { /*function body*/ } ("argument val"))
Or
;(function(arguments){ /*function body*/ })("argument val")
NOTE the inclusion of the ; befor the function. This is very important as the open "(" will prevent automatic semicolon insertion on any code above the function.
Immediately invoked function expression.
const functionResult = (function (arguments) {
/*function body*/
return functionResult;
}());
const functionResult = (function (arguments) {
/*function body*/
return functionResult;
})();
As a var or block scopedconst, let
Anonymous callback.
With ES6 you should use the arrow function syntax rather than anonymous function expressions.
myArray.forEach((item,i) => {/*function body*/});
myArray.filter(item => !item);
setTimeout(() => {/*function body*/}, 1000);
Function as properties.
Using the object declaration function shorthand syntax.
var myObj = {
functionName (arguments) {/*function body*/},
}
// called
myObj.functionName("arg");
is preferable over
var myObj = {
functionName : function (arguments) {/*function body*/},
}
Or via function object declarations
function MyObjectFunction(arguments){
this.propertyFunction = function(arguments) { /*function body*/ }
// or arrow notation is fine
this.propertyFunction = (argument) => { /*function body*/ };
}
Functions as prototypes
function MyObj (arguments) {
MyObj.prototype.functionName = function(arguments) { /*function body*/ }
}
or
function MyObj (arguments) {}
MyObj.prototype.functionName = function(arguments) { /*function body*/ }
or
MyObj.prototype = {
functionName(arguments) { /*function body*/ }
}
Defining a prototype function is useful when creating constructors or 'classes' in JavaScript. e.g. a func that you will new
var MyClass = function(){};
MyClass.prototype.doFoo = function(arg){ bar(arg); }
but is of no use in plain old library functions e.g.
function doPopup(message){ /* create popup */};
There are several benefits of using a prototype function including but not limited to
speed
memory usage
extensibility
But, again, this is in the context of creating constructors for instantiable 'classes'
HTH
It works like so:
(function(){ // create an isolated scope
// My Object we created directly
var myObject = {
a: function(x,y) {
console.log('a');
},
b: function(x,y) {
console.log('b');
this.a(x,y);
}
};
})();
(function(){ // create an isolated scope
// Create a Object by using a Class + Constructor
var myClass = function(x,y) {
console.log('myClass: constructor');
this.b(x,y);
};
myClass.prototype = {
a: function(x,y) {
console.log('myClass: a');
},
b: function(x,y) {
console.log('myClass: b');
this.a(x,y);
}
};
// Define a function that should never inherit
myClass.c = function(x,y) {
console.log('myClass: c');
this.a(x,y);
};
// Create Object from Class
var myObject = new myClass();
// Will output:
// myClass: constructor
// myClass: b
// myClass: a
// Define a function that should never inherit
myObject.d = function(x,y) {
console.log('myObject: d');
this.a(x,y);
};
// Test the world is roung
console.log(typeof myClass.c, 'should be undefined...');
console.log(typeof myClass.d, 'should be function...');
})();
(function(){ // create an isolated scope
// If you are using a framework like jQuery, you can obtain inheritance like so
// Create a Object by using a Class + Constructor
var myClass = function(x,y) {
console.log('myClass: constructor');
this.b(x,y);
};
myClass.prototype = {
a: function(x,y) {
console.log('myClass: a');
},
b: function(x,y) {
console.log('myClass: b');
this.a(x,y);
}
};
// Create new Class that inherits
var myOtherClass = function(x,y) {
console.log('myOtherClass: constructor');
this.b(x,y);
};
$.extend(myOtherClass.prototype, myClass.prototype, {
b: function(x,y) {
console.log('myOtherClass: b');
this.a(x,y);
}
});
// Create Object from Class
var myOtherObject = new myOtherClass();
// Will output:
// myOtherClass: constructor
// myOtherClass: b
// myClass: a
})();
(function(){ // create an isolated scope
// Prototypes are useful for extending existing classes for the future
// Such that you can add methods and variables to say the String class
// To obtain more functionality
String.prototype.alert = function(){
alert(this);
};
"Hello, this will be alerted.".alert();
// Will alert:
// Hello, this will be alerted.
})();
Edit: Fixed code so that it will actually run in your browser if you copy and paste :-)
Foo is both an Object and a namespace. See this question.
Using objects as namespaces prevents name collisions. That's always a good idea, but especially when you're developing and/or using shared libraries.
If you don't expect to be making multiple Foo objects (and so don't need the object-oriented style), you could create your functions as methods on a singleton object:
var Foo = {}
Foo.bar = function() { ... }
or
var Foo = {
bar: function() {...},
quux: function() {...}
};
You'd then simply call the function as:
Foo.bar()
(This kind of declaration is roughly equivalent to a static method in C++ or Java.)