this code works, but my question is I dont understand the purpose of var that = this. Why do I need to reference it like that to pass it to setInterval. I read about 'this' in http://www.sitepoint.com/what-is-this-in-javascript/, but it doesn't really answer my question
my JavaScript code
function spinClass(imageSource, height, width, forward, el){
this.src = imageSource;
this.spinFoward = forward;
this.element = document.getElementById(el);
this.height = height;
this.width = width;
this.d = 0;
var img = document.createElement("img");
img.setAttribute('src', this.src);
img.setAttribute('height', this.height);
img.setAttribute('width', this.width);
this.element.appendChild(img);
this.letSpin = function letSpin(){
//alert(this.d);
var that = this;
img.style.transform = "rotate(" + this.d + "deg)";
img.style.WebkitTransform= "rotate(" + this.d + "deg)";
img.style.MozTransform= "rotate(" + this.d + "deg)";
img.style.msTransform= "rotate(" + this.d + "deg)";
img.style.OTransform= "rotate(" + this.d + "deg)";
//alert(this.spinFoward);
if (this.spinFoward == true){
this.d++;
}else{
this.d--;
}
setInterval(function(){that.letSpin();}, 20);
};
}
The value of the this keyword is tied to the function it's used within and to how that function was called.
That includes both letSpin() and the short, anonymous function being passed to setTimeout(). And, the anonymous function won't automatically inherit or share the this value from letSpin() just by its placement.
So, you have to either capture the value in a variable with another name.
var that = this;
Or, bind the function so it will use a particular value when it's called.
setTimeout(function(){
this.letSpin();
}.bind(this), 20);
And, with bind, you can also pass the method without the anonymous function.
setTimeout(this.letSpin.bind(this), 20);
Instantiate object with this function:
function newClass(klass) {
var obj = new klass;
$.map(obj, function(value, key) {
if (typeof value == "function") {
obj[key] = value.bind(obj);
}
});
return obj;
}
This will do automatic binding of all function, so you will get object in habitual OOP style,
when methods inside objects has context of its object.
So you instantiate you objects not through the:
var obj = new spinClass();
But:
var obj = newClass(spinClass);
Related
I'm kinda newbie in JS objects, but I'd like to learn correct ways of doing things.
I'm writing a Class and it is mostly based on element that is passed to constructor. I want this element to have an event that updates the object.
I made it so it happens, but this just feels "hacky".
function SomeClass(element) {
this.element = element;
this.mouseX = 0;
this.mouseY = 0;
this.setMousePosition = function(posX, posY) {
this.mouseX = posX;
this.mouseY = posY;
};
this.listenMousePosition = function() {
var obj = this;
$(this.element).on('mousemove',null, {obj: obj}, function(e, obj) {
e.data.obj.setMousePosition(e.offsetX, e.offsetY);
$('#output').html('X: ' + e.data.obj.mouseX + '; Y: ' + e.data.obj.mouseY);
})
}
this.listenMousePosition();
return this;
}
window.contentDiv = new SomeClass($(".content")[0]);
Is there a better way of doing this or is this the way to roll?
As I checked - I can't just pass it to function as you see in link: https://jsfiddle.net/nooorz24/v6f1jydm/7/
At least a couple ways you could do this. The issue here is that when you get inside the function this changes from referencing the class instance to the method.
Reference another variable
By using an external variable, we don't care if this changes.
var self = this;
this.listenMousePosition = function() {
$(self.element).on('mousemove', function(e) {
self.setMousePosition(e.offsetX, e.offsetY);
$('#output').html('X: ' + self.mouseX + '; Y: ' + self.mouseY);
});
};
Use an arrow function
Arrow functions do not change what this references.
this.listenMousePosition = () => {
$(this.element).on('mousemove', e => {
this.setMousePosition(e.offsetX, e.offsetY);
$('#output').html('X: ' + this.mouseX + '; Y: ' + this.mouseY);
});
};
Take note though that arrow functions do not work in IE versions prior to Edge.
This question already has answers here:
Why wouldn't I use Child.prototype = Parent.Prototype rather than Child.prototype = new Parent(); for Javascript inheritance?
(3 answers)
Closed 7 years ago.
Hi I'm new in Javascript OO and want to know more about about inheritance. Hope you can provide some advice!
I see this great post:
How to "properly" create a custom object in JavaScript?
which talks about how a class is inherited as I see in other websites, ex.:
function man(x) {
this.x = x;
this.y = 2;
}
man.prototype.name = "man";
man.prototype.two = function() {
this.y = "two";
}
function shawn() {
man.apply(this, arguments);
};
shawn.prototype = new man;
The above post claims that in order not to call "man"'s constructor while inheriting, one can use a helper like this instead:
function subclassOf(base) {
_subclassOf.prototype= base.prototype;
return new _subclassOf();
}
function _subclassOf() {};
shawn.prototype = subclassOf(man);
While I understand its intention, I don't see why we can't call
shawn.prototype = man.prototype;
I see it works exactly the same. Or is there something I'm missing? Thanks in advance!
Well, examples are better than words in my humble opinion. All below examples are using your code, with some additions.
The first example will prove that using shawn.prototype = new man; you're calling the constructor twice
function man(h, w) {
SendMessage("man is created with height " + h + " and weight " + w);
this.height = h;
this.weight = w;
}
man.prototype.name = "man";
man.prototype.double = function() {
this.height *= 2;
this.weigth *= 2;
}
function shawn() {
man.apply(this, arguments);
};
function SendMessage(msg) {
document.getElementById("Console").innerHTML += msg + "<br />";
}
window.onload = function() {
shawn.prototype = new man;
var p = new shawn(180, 90);
SendMessage("Shawn height: " + p.height);
}
<div id="Console"></div>
As you see, the constructor is called twice - once with no arguments then with the actual arguments you give it.
The second example just proves that using the subclassOf solve that "double calling" issue.
function man(h, w) {
SendMessage("man is created with height " + h + " and weight " + w);
this.height = h;
this.weight = w;
}
man.prototype.name = "man";
man.prototype.double = function() {
this.height *= 2;
this.weigth *= 2;
}
function shawn() {
man.apply(this, arguments);
};
function subclassOf(base) {
_subclassOf.prototype= base.prototype;
return new _subclassOf();
}
function _subclassOf() {};
function SendMessage(msg) {
document.getElementById("Console").innerHTML += msg + "<br />";
}
window.onload = function() {
shawn.prototype = subclassOf(man);
var p = new shawn(180, 90);
SendMessage("Shawn height: " + p.height);
}
<div id="Console"></div>
The third example shows what's wrong with your idea of shawn.prototype = man.prototype and I'll explain. shawn inherits from man so I've added new method that should affect only shawn, called marriage (that of course cause him to gain some weight ;)) - that method should not affect the base class man as it's not inheriting from shawn, inheritance is one way only. But.... as you see in the example, ordinary man can also get married - big problem.
function man(h, w) {
SendMessage("man is created with height " + h + " and weight " + w);
this.height = h;
this.weight = w;
}
man.prototype.name = "man";
man.prototype.double = function() {
this.height *= 2;
this.weight *= 2;
}
function shawn() {
man.apply(this, arguments);
};
function SendMessage(msg) {
document.getElementById("Console").innerHTML += msg + "<br />";
}
window.onload = function() {
shawn.prototype = man.prototype;
var p = new shawn(180, 90);
SendMessage("Shawn height: " + p.height);
p.double();
SendMessage("Shawn height: " + p.height);
shawn.prototype.marriage = function() {
SendMessage("Shawn is getting married, current weight: " + this.weight);
this.weight += 20;
};
p.marriage();
SendMessage("Shawn weight: " + p.weight);
var q = new man(170, 60);
q.marriage();
SendMessage("q weight: " + q.weight);
}
<div id="Console"></div>
Finally, the fourth example shows that using the subclassOf everything work fine, as shawn inherits man properly, and marriage is not passed to the base class.
function man(h, w) {
SendMessage("man is created with height " + h + " and weight " + w);
this.height = h;
this.weight = w;
}
man.prototype.name = "man";
man.prototype.double = function() {
this.height *= 2;
this.weight *= 2;
}
function shawn() {
man.apply(this, arguments);
};
function subclassOf(base) {
_subclassOf.prototype= base.prototype;
return new _subclassOf();
}
function _subclassOf() {};
function SendMessage(msg) {
document.getElementById("Console").innerHTML += msg + "<br />";
}
window.onload = function() {
shawn.prototype = subclassOf(man);
var p = new shawn(180, 90);
SendMessage("Shawn height: " + p.height);
p.double();
SendMessage("Shawn height: " + p.height);
shawn.prototype.marriage = function() {
SendMessage("Shawn is getting married, current weight: " + this.weight);
this.weight += 20;
};
p.marriage();
SendMessage("Shawn weight: " + p.weight);
var q = new man(170, 60);
if (q.marriage)
q.marriage();
else
SendMessage("marriage is undefined for man");
SendMessage("q weight: " + q.weight);
}
<div id="Console"></div>
Hope this makes some sense! :)
shawn.prototype = man.prototype;
will share the prototypes, ie modifying one will modify the other.
shawn.prototype = new man;
will set shawn.prototype to a newly created object which inherits from man.prototype and thus changes to it won't propagate to man instances.
However, using new means that the constructor man() will be executed, which can have undesired side-effects.
It's better to manually clone the prototype via
shawn.prototype = Object.create(man.prototype);
if available or a custom clone function (which works the same way as your subclassOf)
shawn.prototype = clone(man.prototype);
otherwise.
In addition to #Shadow's excellent answer, you can think of shawn.prototype = man.prototype as meaning "shawn is the same as man", rather than, "shawn is a man"
I'm trying to change a position of a image that I have in HTML by using javascript. I can actually get it working if I have the following code:
function main()
{
var catOne = document.getElementById("cat1");
catOne.style.left = cat1.getX().toString() + "px";
catOne.style.top = cat1.getY().toString() + "px";
}
but when I change the code to this:
var catOne = new Cat("cat1", 300, 100);
function main()
{
catOne.setUp();
}
it doesn't work. and I dont know why, but it only gives me an error of "TypeError: Cannot read property 'style' of null"
This is my Cat class in javascript:
function Cat(id, x, y)
{
this.cat = document.getElementById(id);
this.x = x;
this.y = y;
}
Cat.prototype.setUp = function ()
{
this.cat.style.left = this.x.toString() + "px";
this.cat.style.top = this.y.toString() + "px";
};
Cat.prototype.getX = function ()
{
return this.x;
};
Cat.prototype.getY = function ()
{
return this.y;
};
TypeError: Cannot read property 'style' of null means your catOne does not exist in the DOM tree.
You should instantiate the Cat class when the DOM is ready (or on window load).
I don't know why you need that main() function but when does it execute? It should also execute when the DOM is ready.
var catOne;
function main() {
catOne.setUp();
}
window.onload = function() {
catOne = new Cat("cat1", 300, 100);
main();
}
I also suggest that you set the position of your cat to absolute if you are positioning it like that in your setUp() function. (I think you are already doing this with your CSS):
Cat.prototype.setUp = function ()
{
this.cat.style.position = 'absolute';
this.cat.style.left = this.x.toString() + "px";
this.cat.style.top = this.y.toString() + "px";
};
Here is the fiddle.
Other than that your code should work.
with:
var catOne = new Cat("cat1", 300, 100);
catOne.setUp();
works just fine.
I don't quite get it how You managed to get error You mentioned
link: http://jsfiddle.net/Z74mM/
have an object of a class Abon and then i want this object to move around the page.
a = new Abon();
a.init();
a.move();
the method move() contains:
function abon_move () {
var x = this.x;
var y = this.y;
var direction_x = Math.random()*5 - 5;
var direction_y = Math.random()*5 - 5;
var x_new = x + direction_x * this.movement_rate;
var y_new = y + direction_y * this.movement_rate;
console.log(x_new+" "+y_new)
$(".abonent."+this.id).animate( {
left:+x_new,
top:+y_new
}, 'slow', "linear", function() { this.move() });
}
All i want is that the method move (represented as function abon_move()) repeated again and again, after the animate stops. But the problem is that this.move() shown in callback has no connection to my object, because this in that place points to the HTML element, selected by jQuery.
UPD:
function Abon(id) {
...
this.move = abon_move;
...
}
Abon.prototype.move = abon_move;
And the actual method is the same, but with no callback in animate
then i try doing the following:
setInterval( a[0].move , 300); //doesn't work - says `this` members are undefined
setInterval( a[0].move() , 300); //works only one time and stops
Thank you for any help!
Try this :
function abon_move () {
var x = this.x;
var y = this.y;
var class = this;
...
}
Then, inside your jQuery animate, your can refer to your class using the variable class
Wrap the function abon_move() in a setTimeout call, as such: setTimeout(abon_move, 300); so it will run every 300 ms.
This question already has answers here:
Why wouldn't I use Child.prototype = Parent.Prototype rather than Child.prototype = new Parent(); for Javascript inheritance?
(3 answers)
Closed 7 years ago.
Hi I'm new in Javascript OO and want to know more about about inheritance. Hope you can provide some advice!
I see this great post:
How to "properly" create a custom object in JavaScript?
which talks about how a class is inherited as I see in other websites, ex.:
function man(x) {
this.x = x;
this.y = 2;
}
man.prototype.name = "man";
man.prototype.two = function() {
this.y = "two";
}
function shawn() {
man.apply(this, arguments);
};
shawn.prototype = new man;
The above post claims that in order not to call "man"'s constructor while inheriting, one can use a helper like this instead:
function subclassOf(base) {
_subclassOf.prototype= base.prototype;
return new _subclassOf();
}
function _subclassOf() {};
shawn.prototype = subclassOf(man);
While I understand its intention, I don't see why we can't call
shawn.prototype = man.prototype;
I see it works exactly the same. Or is there something I'm missing? Thanks in advance!
Well, examples are better than words in my humble opinion. All below examples are using your code, with some additions.
The first example will prove that using shawn.prototype = new man; you're calling the constructor twice
function man(h, w) {
SendMessage("man is created with height " + h + " and weight " + w);
this.height = h;
this.weight = w;
}
man.prototype.name = "man";
man.prototype.double = function() {
this.height *= 2;
this.weigth *= 2;
}
function shawn() {
man.apply(this, arguments);
};
function SendMessage(msg) {
document.getElementById("Console").innerHTML += msg + "<br />";
}
window.onload = function() {
shawn.prototype = new man;
var p = new shawn(180, 90);
SendMessage("Shawn height: " + p.height);
}
<div id="Console"></div>
As you see, the constructor is called twice - once with no arguments then with the actual arguments you give it.
The second example just proves that using the subclassOf solve that "double calling" issue.
function man(h, w) {
SendMessage("man is created with height " + h + " and weight " + w);
this.height = h;
this.weight = w;
}
man.prototype.name = "man";
man.prototype.double = function() {
this.height *= 2;
this.weigth *= 2;
}
function shawn() {
man.apply(this, arguments);
};
function subclassOf(base) {
_subclassOf.prototype= base.prototype;
return new _subclassOf();
}
function _subclassOf() {};
function SendMessage(msg) {
document.getElementById("Console").innerHTML += msg + "<br />";
}
window.onload = function() {
shawn.prototype = subclassOf(man);
var p = new shawn(180, 90);
SendMessage("Shawn height: " + p.height);
}
<div id="Console"></div>
The third example shows what's wrong with your idea of shawn.prototype = man.prototype and I'll explain. shawn inherits from man so I've added new method that should affect only shawn, called marriage (that of course cause him to gain some weight ;)) - that method should not affect the base class man as it's not inheriting from shawn, inheritance is one way only. But.... as you see in the example, ordinary man can also get married - big problem.
function man(h, w) {
SendMessage("man is created with height " + h + " and weight " + w);
this.height = h;
this.weight = w;
}
man.prototype.name = "man";
man.prototype.double = function() {
this.height *= 2;
this.weight *= 2;
}
function shawn() {
man.apply(this, arguments);
};
function SendMessage(msg) {
document.getElementById("Console").innerHTML += msg + "<br />";
}
window.onload = function() {
shawn.prototype = man.prototype;
var p = new shawn(180, 90);
SendMessage("Shawn height: " + p.height);
p.double();
SendMessage("Shawn height: " + p.height);
shawn.prototype.marriage = function() {
SendMessage("Shawn is getting married, current weight: " + this.weight);
this.weight += 20;
};
p.marriage();
SendMessage("Shawn weight: " + p.weight);
var q = new man(170, 60);
q.marriage();
SendMessage("q weight: " + q.weight);
}
<div id="Console"></div>
Finally, the fourth example shows that using the subclassOf everything work fine, as shawn inherits man properly, and marriage is not passed to the base class.
function man(h, w) {
SendMessage("man is created with height " + h + " and weight " + w);
this.height = h;
this.weight = w;
}
man.prototype.name = "man";
man.prototype.double = function() {
this.height *= 2;
this.weight *= 2;
}
function shawn() {
man.apply(this, arguments);
};
function subclassOf(base) {
_subclassOf.prototype= base.prototype;
return new _subclassOf();
}
function _subclassOf() {};
function SendMessage(msg) {
document.getElementById("Console").innerHTML += msg + "<br />";
}
window.onload = function() {
shawn.prototype = subclassOf(man);
var p = new shawn(180, 90);
SendMessage("Shawn height: " + p.height);
p.double();
SendMessage("Shawn height: " + p.height);
shawn.prototype.marriage = function() {
SendMessage("Shawn is getting married, current weight: " + this.weight);
this.weight += 20;
};
p.marriage();
SendMessage("Shawn weight: " + p.weight);
var q = new man(170, 60);
if (q.marriage)
q.marriage();
else
SendMessage("marriage is undefined for man");
SendMessage("q weight: " + q.weight);
}
<div id="Console"></div>
Hope this makes some sense! :)
shawn.prototype = man.prototype;
will share the prototypes, ie modifying one will modify the other.
shawn.prototype = new man;
will set shawn.prototype to a newly created object which inherits from man.prototype and thus changes to it won't propagate to man instances.
However, using new means that the constructor man() will be executed, which can have undesired side-effects.
It's better to manually clone the prototype via
shawn.prototype = Object.create(man.prototype);
if available or a custom clone function (which works the same way as your subclassOf)
shawn.prototype = clone(man.prototype);
otherwise.
In addition to #Shadow's excellent answer, you can think of shawn.prototype = man.prototype as meaning "shawn is the same as man", rather than, "shawn is a man"