Class.method = function () { this.xx }
Class.prototype.method = function () { this.xx }
var clazz = new Class();
clazz.method();
When I call the 4th line this in the function will refer to clazz
But when Class.method() is executed, what will this refer to?
this within the Class.prototype.method function will still refer to the Class instance. This isn't a static method, a static (i.e. one per class) method would be something like:
Class.method = function () {
// I am a static method
};
For example:
var Example = function () {
this.name = "DefaultName";
};
Example.prototype.setName = function (name) {
this.name = name;
}
var test = new Example();
test.setName("foo");
console.log(test.name); // "foo"
If you call .method() on your constructor function itself (without new), this will still be bound to the Class object. The this value always depends on the type of invocation, since you are calling the function from within an object (= a method), this will be bound to that context.
Class = function() {
this.xx = "hello";
}
Class.method = function () { this.xx }
Class.prototype.method = function () { alert(this.xx) }
var clazz=new Class();
clazz.method(); // display "hello";
Class.method() // undefined
it will refer to the object calling the Class.method function.
Related
I have a context function type that is defined as below:
var Context = function () {
this.run = function () {
method1();
method2();
}
var method1 = function () {
}
}
As it is clear in the definition, method2 is not defined in the context. I need every instance of Context passes its implementation of this method.
var c = new Context();
// This does not work! because the call in run() function
// is not this.method2();
c.method2 = function () {
alert("injected method2");
};
c.run();
I need to keep method2() in run without use of this object i.e. this.method2();
Any solution?
If you can define method2 before creating Context it will work no problem:
function method2() {
alert(2);
}
var c = new Context();
c.run();
You can add method2 to the window object instead of the c object, in which case it will work.
Note that this is a clear indicator of poor design. You should probably look into doing this differently.
Callback approach:
var Context = function (callback) {
this.run = function () {
method1();
if(callback) callback();
}
var method1 = function () {
}
}
var c = new Context(function () {
alert("injected method2");
});
c.run();
If you change your run method to the following it should work as expected
this.run = function () {
method1();
this.method2();
}
UPDATE: I just realized it looks like you want to be able to do this on all instances of Context objects. In that case you would also need to define method2 on Context.prototype and not just on c
Context.prototype.method2 = function () {
console.log("injected method2dfd");
};
I am trying to create a simple callback system that would fire upon hitting a button. Rather than the callback being a factory function, it is a prototype method of a different object. I've gotten it to work but I don't understand it. Why do I need to use .bind(object) to get the object to fire its method? Originally I tried no bind, and then bind(this), which both failed.
function Bar() {}
Bar.prototype = {
getStuff: function () {
return "Hello";
},
setStuff: function () {
console.log( this.getStuff() );
}
}
function Foo() {
this.afterSubmit = null;
var self = this;
$('button').click(function () {
self.submit()
});
return this;
}
Foo.prototype = {
submit: function () {
if (this.afterSubmit !== null) {
this.afterSubmit();
}
$('#msg').append('clicked ');
return this;
},
setAfterSubmit: function (callback) {
this.afterSubmit = callback;
return this;
}
}
var bar = new Bar();
var foo = new Foo().setAfterSubmit(bar.setStuff.bind(bar));
// Why do I need to bind bar ?
Please take a look at my fiddle
https://jsfiddle.net/j5qfuzna/
this.afterSubmit();
This is setting the context to the Foo instance. Binding it to the Bar instance prevents that from happening.
It is comfortable to create self = this variable. In all methods we always can use self, and don't worry about method context - some times this in method not we expected.
But in prototype method we can't use this hint;
Look at the example (jQuery needed onle to show the question)
var myClass = function () {
this.propery = 'someData';
var self = this;
this.method = function () {
console.log(self.propery);
}
}
myClass.prototype.method2 = function () {
// want to use self here
console.log(this);
}
var my = new myClass();
var eventBus = $({});
eventBus.bind('onMyEvent', my.method);
eventBus.bind('onMyEvent', my.method2);
eventBus.trigger('onMyEvent');
What is the best way to declare the class with possibility to use self in prototype methods?
You don't need self, just need to set the value of this by binding the object to the function:
var MyClass = function () {
this.property = 'someData';
this.method = function () {
console.log(this.property);
};
};
MyClass.prototype.method2 = function () {
console.log(this);
};
var my = new MyClass();
var eventBus = $({});
eventBus.bind('onMyEvent', my.method.bind(my)); // bind
eventBus.bind('onMyEvent', my.method2.bind(my)); // bind
eventBus.trigger('onMyEvent');
everybody!
Suppose that I have this class in JavaScript:
function Animal()
{
this.name = "name";
}
Animal.prototype.someMethod =
function ()
{
}
and this subclass:
function Cat()
{
Animal.call(this);
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
Cat.prototype.someMethod =
function ()
{
// I want to access the superclass "name" instance variable here
}
What's the syntax to access the superclass "name" instance variable from the overriden method in the Cat class?
Thank you.
Marcos
UPDATED: Well, if you want to see the real code, here it is. The problem is with the abc variable (just a test variable that I was using).
var pesquisaAcervo;
$(
function ()
{
carregadoBase();
if ($("#form\\:tipoPesquisa").val() == "SIMPLES")
{
pesquisaAcervo = new PesquisaAcervoSimples();
}
else
{
pesquisaAcervo = new PesquisaAcervoAvancada();
}
pesquisaAcervo.paginaCarregada();
}
);
// --- PesquisaAcervo ----------------------------------------------------------
function PesquisaAcervo()
{
$("*:visible[id^='form:materiaisPesquisa']").
change(this.materialMudado).keyup(this.materialMudado);
this.abc = 10;
}
PesquisaAcervo.prototype.paginaCarregada =
function ()
{
$("#cabecalhoPesquisa a").click(this.exibirDicasPesquisa);
$("#cabecalhoPesquisa select").
change(function () {$("#form").submit();}).
keyup(function () {$(this).change();});
$("*:visible[class*='foco']").focus().select();
};
PesquisaAcervo.prototype.materialMudado =
function ()
{
};
PesquisaAcervo.prototype.exibirDicasPesquisa =
function ()
{
};
// --- PesquisaAcervoSimples ---------------------------------------------------
function PesquisaAcervoSimples()
{
PesquisaAcervo.call(this);
$("#form\\:campos").change(
function ()
{
$("#textoCampo").text($("#form\\:campos :selected").text() + ":");
}
).keyup(function () {$(this).change();}).change();
$("#pesquisaSimples a").click(
function ()
{
pesquisaAcervo = new PesquisaAcervoAvancada();
$("#pesquisaSimples").parent().hide();
$("#pesquisaAvancada").parent().show();
$("#form\\:tipoPesquisa").val("AVANCADO");
}
);
}
PesquisaAcervoSimples.prototype = new PesquisaAcervo();
PesquisaAcervoSimples.prototype.constructor = PesquisaAcervoSimples;
PesquisaAcervoSimples.prototype.materialMudado =
function ()
{
alert(this.abc); // "undefined" here
};
// --- PesquisaAcervoAvancada --------------------------------------------------
function PesquisaAcervoAvancada()
{
PesquisaAcervo.call(this);
}
PesquisaAcervoAvancada.prototype = new PesquisaAcervo();
PesquisaAcervoAvancada.prototype.constructor = PesquisaAcervoAvancada;
Your actual code reveals the problem. The issue is with how you're calling materialMudado. It's being invoked as the callback for an event. The keyword this inside the callback will refer to the target of the event (which has no abc property), not to the object that the function "belongs" to.
Here's a simple demonstration:
function Test() {};
Test.prototype.callback = function() {
alert(this);
}
var t = new Test();
$(document).click(t.callback);
Output (after clicking page):
[object HTMLDocument]
Compare to this:
function Test() {};
Test.prototype.callback = function() {
alert(this);
}
var t = new Test();
$(document).click(function() {
t.callback();
});
Output:
[object Object]
In this second example we close over the variable t, retaining a reference to it.
Applying this to your example produces something like this:
function PesquisaAcervo() {
var that = this;
var callback = function() {
that.materialMudado();
};
$("*:visible[id^='form:materiaisPesquisa']").
change(callback).keyup(callback);
this.abc = 10;
}
this.name should work. I don't see you overriding the name property in your Cat function so you should be able to just do this.name and the protopical chain will do the work to find the first instance of this property which should be Animal.name.
There is no such thing as an override for an instance variable. An instance variable is just a property on the this object. You can read it with:
var x = this.name;
or assign to it with:
this.name = "foo";
this.name will access the name whether you have an instance of an Animal object or an instance of a Cat object.
If you want to assign to the name property in the Cat constructor, you can just do so with
this.name = "Cat";
Once you have a working instance of an object, properties are just properties and there is no distinction for whether a property was created by a superclass or a subclass. They're just properties of the object at that point and you access all of them the same way with the this.propertyName syntax.
Just use the this keyword:
function Animal()
{
this.name = "name";
}
Animal.prototype.someMethod2 =
function ()
{
}
function Cat()
{
Animal.call(this);
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
Cat.prototype.someMethod =
function ()
{
alert(this.name);// I want to access the superclass "name" instance variable here
}
var c = new Cat();
c.someMethod();
Add this code to the bottom, I've just added an alert to your someMethod method...
In your example, Cat derives everything from Animal, so it has access to the name variable
I have an existing class I need to convert so I can append functions like my_class.prototype.my_funcs.afucntion = function(){ alert(private_var);} after the main object definition. What's the best/easiest method for converting an existing class to use this method? Currently I have a JavaScript object constructed like this:
var my_class = function (){
var private_var = '';
var private_int = 0
var private_var2 = '';
[...]
var private_func1 = function(id) {
return document.getElementById(id);
};
var private_func2 = function(id) {
alert(id);
};
return{
public_func1: function(){
},
my_funcs: {
do_this: function{
},
do_that: function(){
}
}
}
}();
Unfortunately, currently, I need to dynamically add functions and methods to this object with PHP based on user selected settings, there could be no functions added or 50. This is making adding features very complicated because to add a my_class.my_funcs.afunction(); function, I have to add a PHP call inside the JS file so it can access the private variables, and it just makes everything so messy.
I want to be able to use the prototype method so I can clean out all of the PHP calls inside the main JS file.
Try declaring your "Class" like this:
var MyClass = function () {
// Private variables and functions
var privateVar = '',
privateNum = 0,
privateVar2 = '',
privateFn = function (arg) {
return arg + privateNum;
};
// Public variables and functions
this.publicVar = '';
this.publicNum = 0;
this.publicVar2 = '';
this.publicFn = function () {
return 'foo';
};
this.publicObject = {
'property': 'value',
'fn': function () {
return 'bar';
}
};
};
You can augment this object by adding properties to its prototype (but they won't be accessible unless you create an instance of this class)
MyClass.prototype.aFunction = function (arg1, arg2) {
return arg1 + arg2 + this.publicNum;
// Has access to public members of the current instance
};
Helpful?
Edit: Make sure you create an instance of MyClass or nothing will work properly.
// Correct
var instance = new MyClass();
instance.publicFn(); //-> 'foo'
// Incorrect
MyClass.publicFn(); //-> TypeError
Okay, so the way you're constructing a class is different than what I usually do, but I was able to get the below working:
var my_class = function() {
var fn = function() {
this.do_this = function() { alert("do this"); }
this.do_that = function() { alert("do that"); }
}
return {
public_func1: function() { alert("public func1"); },
fn: fn,
my_funcs: new fn()
}
}
var instance = new my_class();
instance.fn.prototype.do_something_else = function() {
alert("doing something else");
}
instance.my_funcs.do_something_else();
As to what's happening [Edited]:
I changed your my_funcs object to a private method 'fn'
I passed a reference to it to a similar name 'fn' in the return object instance so that you can prototype it.
I made my_funcs an instance of the private member fn so that it will be able to execute all of the fn methods
Hope it helps, - Kevin
Maybe I'm missing what it is you're trying to do, but can't you just assign the prototype to the instance once you create it? So, first create your prototype object:
proto = function(){
var proto_func = function() {
return 'new proto func';
};
return {proto_func: proto_func};
}();
Then use it:
instance = new my_class();
instance.prototype = proto;
alert(instance.prototype.proto_func());