Unsure if I've phrased this correctly, but in the callback how do I reference the controls property of the base class?
This has been bugging me for some time and I usually work around it, but I'd be grateful if anybody can enlighten me on how I should do this properly.
var base = function() {
var controls = {};
return {
init: function(c) {
this.controls = c
},
foo: function(args) {
this.init(args.controls);
$(this.controls.DropDown).change(function() {
$(this.controls.PlaceHolder).toggle();
});
}
}
};
Much Obliged,
Paul
Use the power of closures:
var base = function() {
var controls = {};
return {
init: function(c) {
this.controls = c
},
foo: function(args) {
var self = this;
this.init(args.controls);
$(this.controls.DropDown).change(function() {
$(self.controls.PlaceHolder).toggle();
});
}
}
};
Although closures are preferred, you could also use jquery bind to pass an object along:
var base = function() {
var controls = {};
return {
init: function(c) {
this.controls = c
},
foo: function(args) {
this.init(args.controls);
$(this.controls.DropDown).bind('change', {controls: this.controls}, function(event) {
$(event.data.controls.PlaceHolder).toggle();
});
}
}
};
You need to leverage closures here.
var base = function() {
var controls = {};
return {
init: function(c) {
this.controls = c
},
foo: function(args) {
this.init(args.controls);
$(this.controls.DropDown).change(function(controls) {
return function(){
$(controls.PlaceHolder).toggle();
}
}(this.controls));
}
}
};
Related
We are using a oop architecture as the following, and we have a scope problem. We have the 'self' variable for saving the context, but when we call the function 'print' in the overridden class, we are using the 'self' variable instead of 'this', and we cannot override a base method.
Do someone knows how override this methods with this architecture?
var baseItem = function() {
var self = {};
self.a = function () {
console.log('base');
return 1;
};
self.print = function() {
return self.a();
}
return self;
};
var middleItem = function () {
var parent = baseItem();
var self = Object.create(parent);
return self;
}
var overrided = function () {
var parent = middleItem();
var self = Object.create(parent);
self.a = function() {
console.log('overrided');
return 55;
};
return self;
}
var obj = overrided();
overrided.print(); // This returns 1 instead 55, as we would want
How would I do the following:
var Parent = function() {
this.Child = {
childFunction: function() {
this.parentFunction();
}
};
this.parentFunction = function() {
}
};
var parentObj = new Parent();
parentObj.Child.childFunction();
At the moment I'm getting "undefined is not a function" because obviously parentFunction() isn't in scope, but I'm not sure what the best way to make it accessible is?
As this in Child will refer to Child object not Parent thus Store the reference of this of Parent in a variable which can be used later in childFunction.
var Parent = function() {
var _self = this; //Store the reference
this.Child = {
childFunction: function() {
_self.parentFunction(); //Use here
}
};
this.parentFunction = function() {
alert('In parentFunction');
}
};
var parentObj = new Parent();
parentObj.Child.childFunction();
var Parent = function() {
this.Child = {
childFunction: function() {
this.parentFunction();
}
};
this.parentFunction = function() {
}
};
Now inside this.Child childFunction this will refer to Child object and not the Parent.
So you must use self/that to refer to the parent.
var Parent = function() {
var that = this;
this.Child = {
childFunction: function() {
that.parentFunction();
}
};
this.parentFunction = function() {
}
};
You can just use Parent.parentFunction() as well.
var Parent = function() {
this.Child = {
childFunction: function() {
Parent.parentFunction();
}
};
this.parentFunction = function() {
}
};
The problem is that this in your childFunction refers to the current object which is Child.
The common solution would be to access the parent using a variable that is available through a closure. For example:
var Parent = function() {
var _this = this;
this.Child = {
childFunction: function() {
_this.parentFunction();
}
};
this.parentFunction = function() {
// ...
}
};
Alternatively, a more cumbersome approach would be to use bind to 'tie' the function context of the childFunction to the current this (which is the parent):
childFunction: function() {
this.parentFunction();
}.bind(this);
See MDN
It's easy to make private variables accessed by public methods of a module you're exporting:
var makeAModule = function() {
var _secret = 'Ssh!';
var module = {
tellMeYourSecret: function() {
console.log(_secret);
}
};
return module;
}
// > var m = makeAModule();
// > m.tellMeYourSecret();
// Ssh!
Sometimes I need to define properties with Object.defineProperty that are computed by getters using the value of other private variables. Those have to go on an object, though, so I end up making a private object just to hold them. If I don't store all my private members on that object, it gets confusing to remember which props are on it and which aren't, so I put everything there:
var makeAModule = function() {
var priv = {};
priv._secret = 'Ssh!';
Object.defineProperty(priv, 'secretLength', {
get: function() {
return priv._secret.length;
}
});
var module = {
tellMeYourSecret: function() {
console.log(priv._secret);
},
howLongIsYourSecret: function() {
console.log(priv._secretLength);
}
}
return module;
}
// > var m = makeAModule();
// > m.howLongIsYourSecret();
// 4
Is there any way to define a variable (not attached to an object) whose value is computed through a getter? Something like this:
var makeAModule = function() {
var _secret = 'Ssh!';
Object.defineVariable('_secretLength', {
get: function() {
return _secret.length;
}
})
var module = {
tellMeYourSecret: function() {
console.log(_secret);
},
howLongIsYourSecret: function() {
console.log(_secretLength);
}
}
return module;
}
Not directly.
However, you can set it as a property of window, thus making it a global variable. But using global variables is not recommendable, specially if they are secret.
var makeAModule = function() {
var priv = {};
priv._secret = 'Ssh!';
Object.defineProperty(window, '_secretLength', {
get: function() {
return priv._secret.length;
}
});
return {
tellMeYourSecret: function() {
return _secret;
},
howLongIsYourSecret: function() {
return _secretLength;
}
};
};
document.body.innerHTML =
"Secret length: " + makeAModule().howLongIsYourSecret();
Alternatively, you can define your getters as properties of an object, and use a with statement. Note that the with statement can't be used in strict mode.
var makeAModule = function() {
var priv = {};
priv._secret = 'Ssh!';
Object.defineProperty(priv, '_secretLength', {
get: function() {
return priv._secret.length;
}
});
with(priv) {
return {
tellMeYourSecret: function() {
return _secret;
},
howLongIsYourSecret: function() {
return _secretLength;
}
};
}
};
document.body.innerHTML =
"Secret length: " + makeAModule().howLongIsYourSecret();
I'm developing a small framework (in JS) and for esthetic reasons and simplicity I was wondering if there could be a way to implement something like PHP "__invoke".
For example:
var myClass = function(config) {
this.config = config;
this.method = function(){};
this.execute = function() {
return this.method.apply(this, arguments);
}
}
var execCustom = new myClass({ wait: 100 });
execCustom.method = function() {
console.log("called method with "+arguments.length+" argument(s):");
for(var a in arguments) console.log(arguments[a]);
return true;
};
execCustom.execute("someval","other");
Desired way to execute:
execCustom("someval","other");
Any ideas? Thanks.
if you are ready to use JS pattern, you can do this in following way:
var myClass = function(opts) {
return function(){
this.config = opts.config;
this.method = opts.method;
return this.method.apply(this, arguments);
};
};
var execCustom = new myClass({
config:{ wait: 100 },
method:function() {
console.log("called method with "+arguments.length+" argument(s):");
for(var a in arguments) console.log(arguments[a]);
return true;
}});
execCustom("someval","other");
jsbin
this is the best way I can think of
UPDATED VERSION (by op)
var myClass = function(opts) {
var x = function(){
return x.method.apply(x, arguments);
};
x.config = opts.config;
x.method = opts.method;
return x;
};
var execCustom = new myClass({
config:{ wait: 100 },
method:function() {
console.log("called method with "+arguments.length+" argument(s):");
for(var a in arguments) console.log(arguments[a]);
return true;
}});
execCustom("someval","other");
jsbin
Just return a function that will form the public interface:
function myClass(config)
{
var pubif = function() {
return pubif.method.apply(pubif, arguments);
};
pubif.config = config;
pubif.method = function() { };
return pubif;
}
The rest of the code remains the same.
I tried to call from child object a parent attribute
var parentObj = {
attr1:1,
attr2:2,
childObj:{
method1:function(){
return this.attr1 * this.attr2;
}
}
}
but it doesn't work.
Try referencing parentObj directly:
var parentObj = {
attr1: 1,
attr2: 2,
childObj: {
method1: function () {
return parentObj.attr1 * parentObj.attr2;
}
}
}
This can be done with the power of closures!
var Construct = function() {
var self = this;
this.attr1 = 1;
this.attr2 = 2;
this.childObj = {
method1: function () {
return self.attr1 * self.attr2
}
}
}
var obj = new Construct();
var parentObj = {
attr1:1,
attr2:2,
childObj:{
method1:function(){
return this.parent.attr1 * this.parent.attr2;
}
},
init:function(){
this.childObj.parent = this;
delete this.init;
return this;
}
}.init();
This is an another approach without referencing the parent object's name.
var parentObj = {
attr1: 1,
attr2: 2,
get childObj() {
var self = this;
return {
method1: function () {
return self.attr1 * self.attr2;
}
}
}
}
Can be accessed as:
parentObj.childObj.method1(); // returns 2
There is a problem with referencing parent object my name because it breaks the app in case you rename it. Here is nicer approach, which I use extensively, where you pass the parent as an argument to the child init method:
var App = {
init: function(){
this.gallery.init(this);
},
somevar : 'Some Var'
}
App.gallery = {
init: function(parObj){
this.parent = parObj;
console.log( this.parent.somevar );
}
}
App.init();