This question already has answers here:
Self-references in object literals / initializers
(30 answers)
Closed 9 years ago.
Sometime ago I heard that it was good practice to wrap your code in a big object to serve as a namespace in order to reduce global namespace cluttering and to facilitate library export, so I tried this.
var wrapper = {
foo: function(){
return 42;
},
bar: this.foo()
};
It fails, claiming that "foo is not defined".
Calling methods before finishing the object declaration is probably bad, so I moved bar, and it worked.
var wrapper = {
foo: function(){
return 42;
},
};
wrapper.bar = wrapper.foo();
I feel that this can become kind of ugly, especially with nested namespaces and such, so are there any workarounds that don't make it hard to see all of the wrapper's members at once?
The problem is that this is going to equal the global context. You need to access the function like so:
var wrapper = {
foo: function(){
return 42;
},
bar: null,
init : function() {
// all initialization code goes here
wrapper.bar = wrapper.foo();
}
};
wrapper.init();
This method is great for organizing your code into logical chunks so you and future developers can easily find what you are looking for in your javascript.
var wrapper = {
foo: (function(){
return 42;
})()
};
alert(wrapper.foo);
http://jsfiddle.net/ee8Ww/
Using this like that will not work unless wrapper is 1) a function, and 2) you instantiate it to use it:
var wrapper = function() {
this.foo = function() { return 42; }
this.bar = this.foo();
};
var wrapperInstance = new wrapper();
alert(wrapperInstance.bar()); // 42
wrapperInstance.foo(); // also works
Related
This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 8 years ago.
I've always been taught the correct way to simulate a class in JavaScript is by adding methods to the prototype outside the function that will be your class, like this:
function myClass()
{
this.myProp = "foo";
}
myClass.prototype.myMethod = function()
{
console.log(this);
}
myObj = new myClass();
myObj.myMethod();
I've been running into the issue that the this in my methods resolves to the global Window object, as explained best on quirksmode.
I've tried doing the var that = this; trick Koch mentions, but since my methods are outside my class, my that variable is no longer in scope. Perhaps I'm just not understanding it completely.
Is there a way I can create a class in JavaScript where methods are not recreated each implementation and this will always point to the object?
EDIT:
The simplified code above works but I've had many times where I declare a "class" exactly like above and when I call myObj.myMethod(), it comes back as a Window object. I've read over every explanation of this that I could find, such as the one I linked to and still don't understand why this problem sometimes happens. Any idea of a situation where the code could be written like above and this would refer to Window?
Here's the implementation I'm currently having problems with, but when I simplify it down like above into a few lines, I no longer have the problem:
HTML File:
<script type="text/javascript" src="./scripts/class.Database.js"></script>
<script type="text/javascript" src="./scripts/class.ServerFunctionWrapper.js"></script>
<script type="text/javascript" src="./scripts/class.DataUnifier.js"></script>
<script type="text/javascript" src="./scripts/main.js"></script>
class.DataUnifier.js:
function DataUnifier()
{
this._local = new Database();
this._server = new ServerFunctionWrapper();
this.autoUpdateIntervalObj = null;
}
DataUnifier.prototype.getUpdates = function()
{
this._server.getUpdates(updateCommands)
{
console.log(updateCommands);
if (updateCommands)
{
executeUpdates(updateCommands);
}
}
}
//interval is in seconds
DataUnifier.prototype.startAutoUpdating = function(interval)
{
this.stopAutoUpdating();
this.autoUpdateIntervalObj = setInterval(this.getUpdates,interval * 1000);
}
DataUnifier.prototype.stopAutoUpdating = function()
{
if (this.autoUpdateIntervalObj !== null)
{
clearInterval(this.autoUpdateIntervalObj);
this.autoUpdateIntervalObj = null;
}
}
main.js
var dataObj = new DataUnifier();
$(document).ready(function ev_document_ready() {
dataObj.startAutoUpdating(5);
}
I've cut out some code that shouldn't matter but maybe it does. When the page loads and dataObj.startAutoUpdating(5) is called, it breaks at the this.stopAutoUpdating(); line because this refers to the Window object. As far as I can see (and according to the link provided), this should refer to the DataUnifier object. I have read many sources on the this keyword and don't understand why I keep running into this problem. I do not use inline event registration. Is there any reason code formatted like this would have this problem?
EDIT 2: For those with similar issues, see "The this problem" half way down the page in this Mozilla docs page: http://developer.mozilla.org/en-US/docs/Web/API/Window.setInterval
My favorite way of defining classes is as follows:
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
Using the defclass function you can define MyClass as follows:
var MyClass = defclass({
constructor: function () {
this.myProp = "foo";
},
myMethod: function () {
console.log(this.myProp);
}
});
BTW your actual problem is not with classes. It's the way you're calling this.getUpdates from setTimeout:
this.autoUpdateIntervalObj = setInterval(this.getUpdates, interval * 1000);
Instead it should be:
this.autoUpdateIntervalObj = setInterval(function (self) {
return self.getUpdates();
}, 1000 * interval, this);
Hence your DataUnifier class can be written as:
var DataUnifier = defclass({
constructor: function () {
this._local = new Database;
this._server = new ServerFunctionWrapper;
this.autoUpdateIntervalObj = null;
},
getUpdates: function () {
this._server.getUpdates(function (updateCommands) {
console.log(updateCommands);
if (updateCommands) executeUpdates(updateCommands);
});
},
startAutoUpdating: function (interval) {
this.stopAutoUpdating();
this.autoUpdateIntervalObj = setInterval(function (self) {
return self.getUpdates();
}, 1000 * interval, this);
},
stopAutoUpdating: function () {
if (this.autoUpdateIntervalObj !== null) {
clearInterval(this.autoUpdateIntervalObj);
this.autoUpdateIntervalObj = null;
}
}
});
Succinct isn't it? If you need inheritance then take a look at augment.
Edit: As pointed out in the comments passing additional parameters to setTimeout or setInterval doesn't work in Internet Explorer versions lesser than 9. The following shim can be used to fix this problem:
<!--[if lt IE 9]>
<script>
(function (f) {
window.setTimeout = f(window.setTimeout);
window.setInterval = f(window.setInterval);
})(function (f) {
return function (c, t) {
var a = [].slice.call(arguments, 2);
return f(function () {
c.apply(this, a);
}, t);
};
});
</script>
<![endif]-->
Since the code is only executed conditionally on Internet Explorer versions lesser than 9 it is completely unobtrusive. Just include it before all your other scripts and your code will work on every browser.
The Answer
The problem is not with this.stopAutoUpdating();, it is with:
setInterval(this.getUpdates, interval * 1000);
When you pass a function like this to setInterval it will be called from the event loop, with no knowledge of the this you have here. Note that this has nothing to do with how a function is defined, and everything to do with how it is called. You can get around it by passing in an anonymous function:
var self = this;
setInterval(function(){ self.getUpdates(); }, interval * 1000);
In any modern engine you can use the much nicer bind:
setInterval(this.getUpdates.bind(this), interval * 1000);
You can also use bind in older engines if you shim it first.
Understanding the Problem
I recommend that you read about call and apply for a better understanding.
Note that when you call a function normally, without using bind, call, or apply, then the this will just be set to whichever object context the function was called from (that is, whatever comes before the .).
Hopefully this helps you understand what I said about this not being about how the function is defined, rather how it is called. Here is an example, where you might not expect this to work, but it does:
// This function is not defined as part of any object
function some_func() {
return this.foo;
}
some_func(); // undefined (window.foo or an error in strict mode)
var obj = {foo: 'bar'};
// But when called from `obj`'s context `this` will refer to obj:
some_func.call(obj); // 'bar'
obj.getX = some_func;
obj.getX(); // 'bar'
An example where you might expect it to work, but it doesn't, along with a couple solutions to make it work again:
function FooBar() {
this.foo = 'bar';
}
FooBar.prototype.getFoo = function() {
return this.foo;
}
var fb = new FooBar;
fb.getFoo(); // 'bar'
var getFoo = fb.getFoo;
// getFoo is the correct function, but we're calling it without context
// this is what happened when you passed this.getUpdates to setInterval
getFoo(); // undefined (window.foo or an error in strict mode)
getFoo.call(fb); // bar'
getFoo = getFoo.bind(fb);
getFoo(); // 'bar'
There is no "correct" way to simulate classes. There are different patterns you could use.
You could stick with the one you are using right now. The code you posted works correctly. Or you could switch to another pattern.
For example Douglas Crockford advocates doing something like this
function myClass() {
var that = {},
myMethod = function() {
console.log(that);
};
that.myMethod = myMethod;
return that;
}
Watch his talk on youtube.
http://youtu.be/6eOhyEKUJko?t=48m25s
I use the style bellow:
function MyClass(){
var privateFunction = function(){
}
this.publicFunction = function(){
privateFunction();
}
}
For me this is much more intuitive than using the prototype way, but you'll reach a similar result combining apply() method.
Also, you have another good patterns, Literal Object Notation, Revealing Module Pattern
But, if you want to change the reference to this associate of a function use the Function.prototype.apply(), you can see at this sample a way to change the global this to your object.
This question already has answers here:
Setting methods through prototype object or in constructor, difference? [duplicate]
(3 answers)
Closed 8 years ago.
What's the difference between defining methods on a prototype individually vs via an object?
Example:
function Example() {
this.Test();
}
Example.prototype.Test = function() {
alert("Example");
};
instead of:
function Example() {
this.Test();
}
Example.prototype = {
Test: function() {
alert("Example");
}
};
It's the difference between adding to the prototype and replacing it.
The only place it's really likely to make a difference is in this sort of scenario, which is relatively rare (and yet, I avoid replacing prototypes because of it):
var f = new Foo();
function Foo() {
}
Foo.prototype = {
test: function() { }
};
f.test(); // Fails!
Live Copy | Live Source
That fails because the f object is created with Foo's original prototype object, but then later you replace that prototype object with a new one. f still uses the old one, which doesn't have the test property on it.
This works:
var f = new Foo();
function Foo() {
}
Foo.prototype.test = test: function() { };
f.test(); // Works
...because you're just adding to the object that f already uses as its prototype. Live Copy | Live Source
Provided f isn't created until after you've replaced Foo.prototype with a new object, it really doesn't make any significant difference.
This question already has answers here:
Use of 'prototype' vs. 'this' in JavaScript?
(15 answers)
Closed 9 years ago.
So, I am not a JavaScript expert, just trying to understand what the difference is between two following snippets of code. I have a project that I want to convert to TypeScript and I need to understand the difference between two code snippets being generated.
var Pony = (function () {
function Pony() { }
Pony.prototype.bite = function () {
alert("Chomp!");
};
return Pony;
})();
var Pony2 = (function () {
function Pony2() {
var self = this;
self.bite = function () {
alert("Chomp!");
};
}
return Pony2;
})();
The difference between the two is that you can get to the prototype of the first Pony via attributes on the object stored in var Pony and could expand upon or use the associated bits of that prototype elsewhere where as Pony2 would just be considered a function. So if you do not plan on using any sort of prototypical inheritance later on they are equivalent.
The answers above give a good overview on the difference between putting on the prototype and putting on the instance. As to your question about converting to TypeScript, below is how you would write them both:
class Pony {
bite(){
alert('chomp');
}
}
class Pony2 {
bite: () => void;
constructor(){
this.bite = () => alert('chomp');
}
}
As far as how you use them, there's no difference. However, from a performance standpoint the former method would be preferable. Let's extend your example a little bit:
var prototypePony1 = new Pony();
var prototypePony2 = new Pony();
var thisPony1 = new Pony2();
var thisPony2 = new Pony2();
prototypePony1.hasOwnProperty('bite'); //returns false
prototypePony2.hasOwnProperty('bite'); //returns false
thisPony1.hasOwnProperty('bite'); //returns true
thisPony2.hasOwnProperty('bite'); //returns true
Pony.prototype.bite = function() { alert('Nomnomnom!'); };
Pony2.prototype.bite = function() { alert('Nomnomnom!'); };
prototypePony1.bite(); //alerts 'Nomnomnom!'
prototypePony2.bite(); //alerts 'Nomnomnom!'
thisPony1.bite(); //alerts 'Chomp!', instance property is accessed first
delete thisPony2.bite;
thisPony2.hasOwnProperty('bite'); //returns false
thisPony2.bite(); //alerts 'Nomnomnom!'
In the example above, thisPony1 and thisPony2 both get their own copy of the bite function, since it was defined using this However, prototypePony1 and prototypePony2 both share the same copy of bite from Pony's constructor.
Once we define the bite prototype on Pony2, the instance property is still accessed first on thisPony1. It's not until we delete the instance property that we see the newly defined prototype property on thisPony2.
For more detailed info on defining object methods, have a look here.
I'm a javascript newbie, and I've come up with the following scheme for namespacing:
(function() {
var ns = Company.namespace("Company.Site.Module");
ns.MyClass = function() { .... };
ns.MyClass.prototype.coolFunction = function() { ... };
})();
Company.namespace is a function registered by a script which simply creates the chain of objects up to Module.
Outside, in non-global scope:
var my = new Company.Site.Module.MyClass();
I'm particularly asking about the method by which I hide the variable ns from global scope - by a wrapping anonymous function executed immediately. I could just write Company.Site.Module everywhere, but it's not DRY and a little messy compared to storing the ns in a local variable.
What say you? What pitfalls are there with this approach? Is there some other method that is considered more standard?
You dont need to scope classes like that, its only necessary if you have global variables outside of the class. I use this approach...
MyApp.MyClass = function() {
};
MyApp.MyClass.prototype = {
foo: function() {
}
};
Also note that I use a object literal for a cleaner prototype declaration
However if you need to scope global variables then you can do
(function() {
var scopedGlobalVariable = "some value";
MyApp.MyClass = function() {
};
MyApp.MyClass.prototype = function() {
foo: function() {
}
};
})();
Your approach looks fine to me.
However, you can also do this slightly different, by returning the "class" from the self-executing function:
Company.Site.Module.MyClass = (function() {
var MyClass = function() { ... };
MyClass.prototype.foo = function() { ... };
return MyClass;
})();
This strips at least all the ns. prefixes. The namespace function can still be utilized to create the objects, but outside of the self-executing function.
This question already has answers here:
this.constructor.prototype -- can't wholly overwrite, but can write individual props?
(2 answers)
Closed 6 years ago.
If I declare the base prototype object outside the constructor for an object, all created objects are based on that single base object which is not suitable for my needs because I need more than one instance of the base object.
In short: Is this code correct? It works but I'm picky about having correct code.
Example:
function BaseObject()
{
BaseObject.prototype.insertObject = function()…
…
… // Some other functions.
}
function Object1()
{
Object1.prototype = new BaseObject();
Object1.prototype.coolFunction = function()…
…
… // Same kind of pattern.
}
function Object2()
{
Object2.prototype = new Object1();
Object2.prototype.incredibleFunction = function()…
…
… // You get the idea.
}
The general pattern:
function Base ( baseMember ) {
this.baseMember = baseMember;
}
Base.prototype.baseFunc = function () {};
function Derived ( baseMember, derivedMember ) {
Base.apply( this, arguments );
this.derivedMember = derivedMember;
}
Derived.prototype = Object.create( Base.prototype );
Derived.prototype.constructor = Derived;
Derived.prototype.derivedFunc = function () {};
It's ugly, I know...
No, all the code that is currently inside your constructor functions should be outside of them. Right now you are reassigning those properties of the prototype every time someone creates a new object.
Finally, points of good-practice:
You should always "fix" the constructor property of any derived prototypes. This is a quirk of JS inheritance; it gets overwritten. People rarely depend on the constructor property being correct, but sometimes they do, and it just feels wrong if you don't.
Object.create(Base.prototype) is better than new Base() if you are working in browsers that support it, or using es5-shim. It only instantiates the object, instead of creating it, which is good since you don't need an actual copy of the object to perform prototypal inheritance.
This would all look like:
function BaseObject() { }
BaseObject.prototype.insertObject = function () { };
function Object1() { }
Object1.prototype = Object.create(BaseObject.prototype);
Object1.prototype.constructor = Object1;
Object1.prototype.coolFunction = function () { };
function Object2() { }
Object2.prototype = Object.create(Object1.prototype);
Object2.prototype.constructor = Object2;
Object2.prototype.incredibleFunction = function () { };