<HTML>
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
function Peon(number) {
this.number = number;
this.inc = function() {
number=number+1;
};
return true;
}
var p=new Peon(10);
function returnNumber() {
p.inc();
alert(p.number);
}
</SCRIPT>
</HEAD>
<BODY>
<INPUT id="b00" TYPE="button" Value="Click" onClick="returnNumber()">
</BODY>
</HTML>
This code doesn't work as intended. Is there a way to make it work without having to write
this.number=this.number+1;
Here it is a trivial choice, but in bigger codes not having this.* would make it a lot more readable. Is it possible?
You can make number "private", but then you need a getter:
function Peon(number) {
var number = number;
// increment
this.inc = function() {
number++;
};
// a simple getter
this.getNumber = function() {
return number;
}
}
var p = new Peon(10);
p.inc();
alert(p.getNumber());
You should read Douglas Crockfords "The Good Parts" for more information on how to use this pattern, there's (limited) a preview available at Google Books.
Also you don't need to return something from the constructor, your return true is superfluous.
No, you have to use this to reference properties on the this object. Note that this in JavaScript is very different from this in some other languages, like C or Java. More here and here.
What your code is doing is accessing the number argument that was passed into the Peon constructor function, rather than the this.number property you created in the constructor. Which is why it doesn't work as intended, but doesn't fail, either.
There's no reason to define your inc operation within the Peon constructor function, BTW, and some good reasons not to (every individual object created via Peon will get its very own copy of that function). So instead, you can define it like this:
function Peon(number) {
this.number = number;
// Don't return values out of constructor functions, it's
// an advanced thing to do. In your case, you were returning
// `true` which was being completely ignored by the JavaScript
// interpreter. If you had returned an object, the `this` object
// created for the `new Peon()` call would have been thrown away
// and the object you returned used instead.
}
Peon.prototype.inc = function() {
++this.number;
};
var p=new Peon(10);
function returnNumber() {
p.inc();
alert(p.number); // alerts 11
}
Not really, but this is a little more concise
this.number++
Actually, as a side note, you'd be better off declaring .inc outside the constructor of Peon. You could do this with prototype. That way the inc function is not reconstructed each time you create an object of type Peon.
Peon.prototype.inc = function(){
this.number++;
}
Or instead of using p.inc() you could do p.number++. That's the only way I can think of avoiding the this keyword.
The only readable way I can see doing it would be:
this.inc = function() {
this.number++;
};
Otherwise, in your "bigger codes" postulation, you could do something like this:
this.inc = function() {
var number = this.number; // obviously simple here. Imagine more complexity
number++;
};
Yes, you do not need to use 'this' in javascript. You can access variables via closure instead of 'this'
function createPeon(number) {
function inc() {
number=number+1;
};
function getNumber() {
return number;
}
return { inc, getNumber };
}
var p=createPeon(10);
p.inc();
alert(p.getNumber());
Related
Let's say I have a method Object.getNumber() and I want to make a small change to the results of that method, for example add 1 to the result, and no I can't access that method's code.
Any way to do this with its prototype? I would need to access the method within the defineProperty call I suppose.
Object.defineProperty(Object.prototype, 'getNumber',{ get: function () { ... } });
You can always replace the original method in the prototype, but keep the original somewhere in the local variable. Something like this:
Object.prototype.getNumber = (function() {
let originalFn = Object.prototype.getNumber;
return function() {
let originalResult = originalFn.apply(this, arguments);
return originalResult + 1;
};
})();
A method is just a function that you can pass around so you can simply apply that function after another:
const getNumber = Object.prototype.getNumber;
Object.prototype.getNumber = function() {
const result = getNumber();
return result + 1;
};
But modifying a native prototype is not good practice, especially Object.prototype as that affects too many things.
While reading other people's source code and various articles over the web, I found that when different people use "object-oriented-style" programming in JavaScript, they often do it quite differently.
Suppose, I want to create a tiny module having 1 property and 1 function. I've seen at least 4 approaches to this task:
// Option 1
var myObject1 = {
myProp: 1,
myFunc: function () { alert("myProp has value " + this.myProp); }
};
// Option 2
var myObject2 = function () {
return {
myProp: 1,
myFunc: function () { alert("myProp has value " + this.myProp); }
};
}();
// Option 3
var MyObject3 = function () {
this.myProp = 1;
this.myFunc = function () { alert("myProp has value " + this.myProp); }
};
var myObject3 = new MyObject3();
// Option 4
var MyObject4 = function () { };
MyObject4.prototype.myProp = 1;
MyObject4.prototype.myFunc = function () { alert("myProp has value " + this.myProp); };
var myObject4 = new MyObject4();
All these approaches are syntactically different but seem to produce objects that can be used in the same way.
What's the semantic difference between them? Are there cases when for some reason I should choose one of these options over all the rest?
myObject1 is an object literal (singleton). Useful in cases where you want to have just one object of this type. Look at it as a static object.
myObject2 returns an object literal. So right after doing var foo = myObject2(), the variable foo will hold the result { myProp: 1, myFunc: function(){...} } with reference to the parent function that has executed. This is called a closure. This can be used to define a public API or modules, for example.
i.e.:
var foo = (function(){
var privateProp = "I am a private property";
// the object below is returned, privateProp is accessible
// only through foo.publicProp
return {
publicProp: privateProp
}
})();
The privateProp property is now accessible through foo.publicProp.
MyObject3 and MyObject4 are constructor functions. By using the new keyword before the function call, you tell JavaScript to create an instance of that object. This means that every new object created this way will inherit properties and methods from the object definition.
The difference between MyObject3 and MyObject4 is that in the case of the former, every instance of that object will have its own copy of the myProp and myFunc properties, whereas the latter will only reference those properties. That means that no matter how many instances of object MyObject4 you create, there will be only one of myProp and myFunc.
I recommend you look up on how closures, prototypal inheritance, and several object design patterns (modules, etc.) work in JavaScript.
Both 1. and 2. are pretty much identical in your example. You could make 2. make an actual difference by declaring "private" variables in the IIFE's scope, like this:
var myObject2 = function () {
var myPrivateProp = ...;
return {
getPrivateProp: function() { return myPrivateProp; }
};
}();
In general, those create a value, not something that you would call a class of values.
Instead, what 3. and 4. are doing is creating a prototype that can be then used to create more usable values out of it. Whether you actually declare the defaults on the prototype or in the constructor doesn't make much difference.
So, to sum up, 1&2 are something like a "lambda" object, without a named prototype, while 3&4 actually make the thing reusable and recreatable.
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.
I'm learning javascript and one thing I keep hearing is "functions are objects". Can you provide some examples for me to better understand this concept?
Sure. Here's some example code:
function Hello() {
alert(Hello.world);
}
Hello.sayHello = Hello;
Hello.world = 'Hello, world!';
Hello.sayHello.sayHello.sayHello.sayHello.sayHello();
Here's proof that it works, too.
Notice how you can assign properties to the function, and assign it to itself and refer to it recursively. It's an object, like most other things in JavaScript, and you can do anything with it. If you've seen prototype inheritance before:
Function.prototype.alert = function() {
alert(this.apply(null, arguments));
};
function add(a, b) {
return a + b;
}
add.alert(1, 2); // Alerts 3
There's a lot here - a function literal, which is a function without a name in essence; prototypical inheritance; methods on functions; dynamic arguments; a function as this.
Here's a quick example on jsBin: http://jsbin.com/enicaj/edit#source
Basically, since functions are objects, they can also have properties and methods.
EDIT: JavaScript inline.
function test(){
return 'hello';
}
test.method = function(){
return ' world';
};
document.write( test() + test.method() );
Outputs 'hello world';
var sayHi = function() {
console.log("hi!");
};
var anotherFunction = function(functionObject) {
functionObject();
};
The function "sayHi" is passed as an object as an argument into the "anotherFunction" function and invoked.
anotherFunction(sayHi);
Use a javascript console like the one included in Chrome to observe this jsFiddle example.
Simplest example of var- function with parameter.
var x = function(message){
alert(message);
};
x('hello world');
x('hello again');
JSFiddle
Yes, you can write a function:
function MyFunction()
{
}
but you can also write
var MyFunction = function()
{
}
you can call both using MyFunction();. There are different reasons for writing them each way, both have their benefits.
Example 1: the function is globally accessible even if you can it before it's defined.
Example 2: the function is extendable as such.
var MyFunction = function()
{
// private methods/properties for use inside object
var privateProperty = 'privatevalue';
var privateFunction = function()
{
return '';
}
// public methods/properties for use outside object
this.propertyName = 'value';
this.publicFunction = function()
{
return privateProperty;
}
}
You can call the public data from the function just as you would an object.
var myobject = new MyFunction()
myobject.publicFunction();
// returns privatevalue;
But the privateProperty var you cannot access.
myobject.privateProperty // will returned undefined variable privateProperty
You can define properties and even methods/functions within the object (function).
That was very much a crash coarse but I hope it helps you understand it a bit more.
In javascript, can I declare properties of an object to be constant?
Here is an example object:
var XU = {
Cc: Components.classes
};
or
function aXU()
{
this.Cc = Components.classes;
}
var XU = new aXU();
just putting "const" in front of it, doesn't work.
I know, that i could declare a function with the same name (which would be also kind of constant), but I am looking for a simpler and more readable way.
Browser-compatibility is not important. It just has to work on the Mozilla platform, as it is for a Xulrunner project.
Thank you a lot!
Cheers.
Since you only need it to work on the Mozilla platform, you can define a getter with no corresponding setter. The best way to do it is different for each of your examples.
In an object literal, there is a special syntax for it:
var XU = {
get Cc() { return Components.classes; }
};
In your second exampe, you can use the __defineGetter__ method to add it to either aXU.prototype or to this inside the constructor. Which way is better depends on whether the value is different for each instance of the object.
Edit: To help with the readability problem, you could write a function like defineConstant to hide the uglyness.
function defineConstant(obj, name, value) {
obj.__defineGetter__(name, function() { return value; });
}
Also, if you want to throw an error if you try to assign to it, you can define a setter that just throws an Error object:
function defineConstant(obj, name, value) {
obj.__defineGetter__(name, function() { return value; });
obj.__defineSetter__(name, function() {
throw new Error(name + " is a constant");
});
}
If all the instances have the same value:
function aXU() {
}
defineConstant(aXU.prototype, "Cc", Components.classes);
or, if the value depends on the object:
function aXU() {
// Cc_value could be different for each instance
var Cc_value = return Components.classes;
defineConstant(this, "Cc", Cc_value);
}
For more details, you can read the Mozilla Developer Center documentation.
UPDATE: This works!
const FIXED_VALUE = 37;
FIXED_VALUE = 43;
alert(FIXED_VALUE);//alerts "37"
Technically I think the answer is no (Until const makes it into the wild). You can provide wrappers and such, but when it all boils down to it, you can redefine/reset the variable value at any time.
The closest I think you'll get is defining a "constant" on a "class".
// Create the class
function TheClass(){
}
// Create the class constant
TheClass.THE_CONSTANT = 42;
// Create a function for TheClass to alert the constant
TheClass.prototype.alertConstant = function(){
// You can’t access it using this.THE_CONSTANT;
alert(TheClass.THE_CONSTANT);
}
// Alert the class constant from outside
alert(TheClass.THE_CONSTANT);
// Alert the class constant from inside
var theObject = new TheClass();
theObject.alertConstant();
However, the "class" TheClass itself can be redefined later on
If you are using Javascript 1.5 (in XUL for example), you can use the const keyword instead of var to declare a constant.
The problem is that it cannot be a property of an object. You can try to limit its scope by namespacing it inside a function.
(function(){
const XUL_CC = Components.classes;
// Use the constant here
})()
To define a constant property, you could set the writable attribute to false in the defineProperty method as shown below:
Code snippet:
var XU = {};
Object.defineProperty(XU, 'Cc', {
value: 5,
writable: false
});
XU.Cc = 345;
console.log(XU.Cc);
Result:
5 # The value hasn't changed