Let's say I have the following code:
var Obj = function() {
this.property = 1;
this.arr = [...] // array containing elements we want to add event listeners to
for (...) {
this.arr[i].addEventListener("click", this.listener, false);
}
}
Obj.prototype.listener = function() {
console.log( this.property ); // DOES NOT WORK! *this* does not point to Obj.
}
var a = new Obj();
How do I access object properties (and methods) within a listener? I would assume I'd need to pass it as a parameter? Is the way I'm going about this structurally wrong?
When the function is called as an event listener, the context (this) is changed to something other that the object itself.
To resolve this, manually bind the context to the object instance in the constructor using bind(). This way, this will always point to the object instance, independent of the calling context:
var Obj = function() {
this.property = 'foo';
this.listener = this.listener.bind(this);
}
Obj.prototype.listener = function() {
console.log(this.property);
}
var a = new Obj();
a.listener.call({});
As suggested by #Tushar, you can use Function.prototype.bind() and pass this.property as parameter
<body>
click
<script>
var Obj = function() {
var obj = this;
this.property = 1;
this.arr = [document.body];
for (var i = 0; i < obj.arr.length; i++) {
obj.arr[i].addEventListener("click"
, obj.listener.bind(obj.arr[i], obj.property), false);
}
}
// note order of parameters; e.g., `prop`, `e`
Obj.prototype.listener = function(prop, e) {
console.log(prop, e); // `1`, `event` object
}
var a = new Obj();
</script>
</body>
Related
Imagine the following....
function MyFunctional()
{
this._internal = "";
}
var foo = new MyFunctional();
foo.bar = 0;
foo.gent = "foobar";
how is it possible to fire an event whenever I call foo.x = y; or foo['x'] = y;? would it be to create a setTimeout and check against the last array of property names? that would seem kinda expensive ^^
Thanks for reading, hopeful for an answer :D
You can do it with proxy object which defines custom behavior for fundamental operations
function MyFunctional() {
this._internal = "";
}
var foo = new MyFunctional();
//define the object whose properties are functions that define the behavior
//of the proxy when an operation is performed on it.
const handler = {
set: function(obj, prop, value) {
if(!(prop in obj)) {
alert(`property '${prop}' added`);
}
obj[prop] = value;
}
}
const p = new Proxy(foo, handler);
p.bar = 0;
p.gent = "foobar";
p.bar = 2;
console.log(foo)
So this is an awkward question to ask, but I'm learning NodeJS and I have a question. In Java when I call a method from an object, the this instance remains the same (as in this example).
private Test inst;
public Test() {
inst = this;
this.myFunction();
}
private void myFunction() {
System.out.println(inst == this);
}
This returns true (in theory, that's code off the top of my head). However, in NodeJS when I attempt to do something similar it fails.
var MyObject = function () {
this.other = new OtherObject();
this.other.on("error", this.onError);
console.log(this); //This returns the MyObject object
}
MyObject.prototype.onError = function (e) {
console.log(this); //This returns the OtherObject object, where I thought it would return the MyObject object.
}
My question is why is this so, and if this is being done incorrectly on my part, how may I correctly reference other variables in the MyObject instance from the onError method?
In JavaScript "methods" are just functions that part of an object.
If you do
var obj = new MyObject();
obj.onError();
The this in onError will be the obj object (because it is the object it is invoked from)
Instead in you case you are passing this.onError to the EventEmitter it will call that function with the EventEmitter (OtherObject) as this.
To avoid that problem use an anonimous function.
var MyObject = function () {
var self = this;
this.other = new OtherObject();
this.other.on("error", function (e) { self.onError(e); });
}
In this way you are binding this back to the object you expect
There is simpler way - you can use bind function.
var EventEmitter = require('events').EventEmitter;
var MyObject = function () {
this.other = new EventEmitter();
this.other.on("error", this.onError.bind(this));
console.log(1, this instanceof MyObject); // 1, true
};
MyObject.prototype.onError = function (e) {
console.log(2, this instanceof MyObject); // 2, true
};
MyObject.prototype.callError = function (e) {
console.log(3, this instanceof MyObject); // 3, true
this.other.emit('error', e);
};
var mo = new MyObject();
mo.callError(new Error(1));
Demo
I could create an object with some methods, and later add a property to it as follows:
var myObj = (function () {
var my = {};
my.method1=function(){}
my.method2=function(){}
my.method3=function(){}
return my;
}());
myObj.myProperty=123;
How could I create the object first and add a property, and then later add the methods afterwards?
myObj={};
myObj.myProperty=123;
//How do I add the above methods to myObj?
I guess there are two solutions:
Merge the objects:
var myObj = {...};
// ...
var objWithMethods = (function() { ... }());
Object.assign(myObj, objWithMethods);
(Object.assign is an ES6 methods. A polyfill can be found in the link, libraries often also provide a method with similar behavior).
Pass the object the methods should be assigned to as argument:
var myObj = {};
myObj = (function (obj) {
var my = obj || {};
my.method1=function(){}
my.method2=function(){}
my.method3=function(){}
return my;
}(myObj));
You can do an extend operation using an existing object
var myObj = {...}
var myAdditionalMethods = { someMethod : function(){ } }
//extend the object
for(var i in myAdditionalMethods)
if(!myObj.hasOwnProperty(i))
myObj[i] = myAdditionalMethods[i];
there are a lot of libraries that have this functionality built in, but that is how you would do it without one
Even prototype can add the functions to original object.
var myObj = function() {
this.myProperty = 123;
}
myObj.prototype.method1 = function method1() {
alert("method1")
}
myObj.prototype.method2 = function method2() {
alert("method2")
}
var newObj = new myObj();
newObj.method1();
newObj.method2();
console.log(newObj)
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());
The entire code snipped is:
var observer = {
addSubscriber: function(callback) {
this.subscribers[this.subscribers.length] = callback;
},
removeSubscriber: function(callback) {
for (var i = 0; i < this.subscribers.length; i++) {
if (this.subscribers[i] === callback) {
delete(this.subscribers[i]);
}
}
},
publish: function(what) {
for (var i = 0; i < this.subscribers.length; i++) {
if (typeof this.subscribers[i] === 'function') {
this.subscribers[i](what);
}
}
},
make: function(o) { // turns an object into a publisher
for(var i in this) {
o[i] = this[i];
o.subscribers = [];
}
}
};
It depends on how it is called. I see it is part of an object literal called observer.
observer.make(o) would mean this == observer.
observer.make.call(otherObj, o) would mean this == otherObj.
new observer.make(o) would make a new object to be this
So it would do something like this.
var model = {
name: 'bike',
id: 4,
gears: 7
};
observer.make(model);
//now model has methods from observer
model.addSubscriber(someListener);
model.publish('gearsChanged');
"this" refers to "observer" assuming that is the object in which it was invoked (and in 99% of cases it is);
so: observer.addSubscriber
in the method addSubscriber, "this" will refer to "observer".
When you have objects within objects (or nodes) it can be confusing to resolve "this":
observer = {
node: $("myDiv"),
callIt: function(){
// note "this.node" - node belongs to observer
this.node.onclick = function(){
// "this" now refers to the "node" object
// onclick was invoked by node
}
}
}
this, is how you refere at the scope of a function. it's the function itsel.!!! this example in prototypejs framework is quite handy.
http://api.prototypejs.org/language/function/prototype/bind/
for example if you the following code.
function foo(){
//here this is foo
var x = {}; //object
var me = this;
var img = new Image();
img.load = function(){
//but here this is img.load.. is the scope of the function =)
// if you want to use the x object you have to assing this FOO a global variable is why you use me = this;
me //is foo :P
}
}