Basically how do I call a base method using this patter below?
var GS = {};
GS.baseClass = function (somedata) {
var that = {};
that.data = somedata;
//Base class method
that.someMethod = function(somedata) {
alert(somedata);
};
return that;
};
GS.derivedClass = function(somedata) {
var that = GS.baseClass(somedata);
//Overwriting base method
that.someMethod = function(somedata) {
//How do I call base method from here?
//do something else
};
return that;
};
Thanks.
var GS = {};
GS.baseClass = function (somedata) {
var that = {};
that.data = somedata;
//Base class method
that.someMethod = function(somedata) {
alert(somedata);
};
return that;
};
GS.derivedClass = function(somedata) {
var that = GS.baseClass(somedata);
//Overwriting base method
var basemethod = that.someMethod;
that.someMethod = function(somedata) {
//How do I call base method from here?
basemethod.apply(that, [somedata]);
//do something else
};
return that;
};
Cheers.
Related
I have some javascript code which looks like this - it's very repetitive, and as you can see follows a very defined pattern:
var AttachmentBuilder = function(){
this.attachment = {};
}
AttachmentBuilder.prototype.text = function(value){
this.attachment.text = value;
return this;
}
AttachmentBuilder.prototype.fallback = function(value){
this.attachment.fallback = value;
return this;
}
AttachmentBuilder.prototype.color = function(value){
this.attachment.color = value;
return this;
}
I had the idea to refactor this like:
var AttachmentBuilder = function(){
this.attachment = {};
}
passThrough(AttachmentBuilder.prototype,"attachment","text");
passThrough(AttachmentBuilder.prototype,"attachment","fallback");
passThrough(AttachmentBuilder.prototype,"attachment","color");
function passThrough(obj, apply, name){
obj[name] = function(param){
this[apply][name] = param;
}
return this;
}
But the context of this is not correct, and it does not behave like the long-hand version.
Below is a working example demoing the working and not working versions.
var AttachmentBuilder_Original = function(){
this.attachment = {};
}
AttachmentBuilder_Original.prototype.text = function(value){
this.attachment.text = value;
return this;
}
AttachmentBuilder_Original.prototype.fallback = function(value){
this.attachment.fallback = value;
return this;
}
AttachmentBuilder_Original.prototype.color = function(value){
this.attachment.color = value;
return this;
}
var original = new AttachmentBuilder_Original();
original.text("Text").color("Red").fallback("Fallback");
console.log("original",original.attachment);
/* ------------------------------------- */
var AttachmentBuilder_New = function(){
this.attachment = {};
}
passThrough(AttachmentBuilder_New.prototype,"attachment","text");
passThrough(AttachmentBuilder_New.prototype,"attachment","fallback");
passThrough(AttachmentBuilder_New.prototype,"attachment","color");
function passThrough(obj, apply, name){
obj[name] = function(param){
this[apply][name] = param;
}
return this;
}
var adjusted = new AttachmentBuilder_New();
adjusted.text("Text").color("Red").fallback("Fallback");
console.log("adjusted",adjusted.attachment);
I'm also interested if there is a more ES6-like way of solving this same issue of repetition.
Your higher order function looks good. Probably simple mistake of putting return statement in the wrong place.
function passThrough(obj, apply, name){
obj[name] = function(param){
this[apply][name] = param;
return this;
} //^^^^^^^^^^^^
}
Your solution should work, if you do this modification.
var AttachmentBuilder = function(){
this.attachment = {};
}
passThrough(AttachmentBuilder.prototype,"attachment","text");
passThrough(AttachmentBuilder.prototype,"attachment","fallback");
passThrough(AttachmentBuilder.prototype,"attachment","color");
function passThrough(obj, apply, name){
obj[name] = function(param){
this[apply][name] = param;
return this;//<---move return this here
}
//return this;
}
I have a sealed object with an array member on which I want to prevent direct pushes.
var myModule = (function () {
"use strict";
var a = (function () {
var _b = {},
_c = _c = "",
_d = [];
Object.defineProperty(_b, "c", {
get: function () { return _c; }
});
Object.defineProperty(_b, "d", {
get { return _d; }
});
_b.addD = function (newD) {
_d.push(newD);
};
Object.seal(_b);
return _b;
}());
var _something = { B: _b };
return {
Something: _something,
AddD: _b.addD
};
}());
myModule.Something.c = "blah"; // doesn't update = WIN!!
myModule.AddD({}); // pushed = WIN!
myModule.Something.d.push({}); // pushed = sadness
How can I prevent the push?
UPDATE:
Thanks for all the thoughts. I eventually need the JSON to send to the server. It looks like I might need to use an object for the array then figure out a way to generate and return the JSON needed, or change _something to use .slice(). Will play and report.
you could override the push method:
var _d = [];
_d.__proto__.push = function() { return this.length; }
and when you need to use it in your module, call Array.prototype.push:
_b.addD = function (newD) {
Array.prototype.push.call(_d, newD);
};
I haven't done any performance tests on this, but this certainly helps to protect your array.
(function(undefined) {
var protectedArrays = [];
protectArray = function protectArray(arr) {
protectedArrays.push(arr);
return getPrivateUpdater(arr);
}
var isProtected = function(arr) {
return protectedArrays.indexOf(arr)>-1;
}
var getPrivateUpdater = function(arr) {
var ret = {};
Object.keys(funcBackups).forEach(function(funcName) {
ret[funcName] = funcBackups[funcName].bind(arr);
});
return ret;
}
var returnsNewArray = ['Array.prototype.splice'];
var returnsOriginalArray = ['Array.prototype.fill','Array.prototype.reverse','Array.prototype.copyWithin','Array.prototype.sort'];
var returnsLength = ['Array.prototype.push','Array.prototype.unshift'];
var returnsValue = ['Array.prototype.shift','Array.prototype.pop'];
var funcBackups = {};
overwriteFuncs(returnsNewArray, function() { return []; });
overwriteFuncs(returnsOriginalArray, function() { return this; });
overwriteFuncs(returnsLength, function() { return this.length; });
overwriteFuncs(returnsValue, function() { return undefined; });
function overwriteFuncs(funcs, ret) {
for(var i=0,c=funcs.length;i<c;i++)
{
var func = funcs[i];
var funcParts = func.split('.');
var obj = window;
for(var j=0,l=funcParts.length;j<l;j++)
{
(function() {
var part = funcParts[j];
if(j!=l-1) obj = obj[part];
else if(typeof obj[part] === "function")
{
var funcBk = obj[part];
funcBackups[funcBk.name] = funcBk;
obj[part] = renameFunction(funcBk.name, function() {
if(isProtected(this)) return ret.apply(this, arguments);
else return funcBk.apply(this,arguments);
});
}
})();
}
}
}
function renameFunction(name, fn) {
return (new Function("return function (call) { return function " + name +
" () { return call(this, arguments) }; };")())(Function.apply.bind(fn));
};
})();
You would use it like so:
var myArr = [];
var myArrInterface = protectArray(myArr);
myArr.push(5); //Doesn't work, but returns length as expected
myArrInterface.push(5); //Works as normal
This way, you can internally keep a copy of the interface that isn't made global to allow your helper funcs to modify the array as normal, but any attempt to use .push .splice etc will fail, either directly, or using the .bind(myArr,arg) method.
It's still not completely watertight, but a pretty good protector. You could potentially use the Object.defineProperty method to generate protected properties for the first 900 indexes, but I'm not sure of the implications of this. There is also the method Object.preventExtensions() but I'm unaware of a way to undo this effect when you need to change it yourself
Thank you, dandavis!
I used the slice method:
var myModule = (function () {
"use strict";
var a = (function () {
var _b = {},
_c = _c = "",
_d = [];
Object.defineProperty(_b, "c", {
get: function () { return _c; }
});
Object.defineProperty(_b, "d", {
get { return _d.slice(); } // UPDATED
});
_b.updateC = function (newValue) {
_c = newValue;
};
_b.addD = function (newD) {
_d.push(newD);
};
Object.seal(_b);
return _b;
}());
var _something = { B: _b };
return {
Something: _something,
AddD: _b.addD
};
}());
myModule.Something.c = "blah"; // doesn't update = WIN!!
myModule.AddD({}); // pushed = WIN!
myModule.Something.d.push({}); // no more update = happiness
This allows me to protect from direct push calls enforcing some logic.
If I have this code
var node = function(n) {
var name = n;
var children = [];
var finished = false;
var failed = false;
this.getName = function() {
return name
};
this.downloadData = function(obj) {
};
this.getChildren = function() {
return children;
};
this.setChildren = function(c) {
Array.prototype.push.apply(children, c);
};
this.isFinished = function() {
return finished;
};
this.setFinished = function() {
finished = true;
}
this.isFailed = function() {
return failed;
}
this.setFailed = function() {
failed = true;
}
};
How can I convert this into an object like:
var a = new node("a");
var j = JSON.stringify(a);
result
{"name":"a","children":[],"finished":false,"failed":false}
thanks
This could be done by implementing the toJSON function.
If an object being stringified has a property named toJSON whose value
is a function, then the toJSON() method customizes JSON
stringification behavior: instead of the object being serialized, the
value returned by the toJSON() method when called will be serialized.
- Mozilla
eg:
var node = function(n) {
var name = n;
var children = [];
var finished = false;
var failed = false;
this.toJson = function toJson() {
return {"name":name ... };
}
}
You need object properties instead of variables.
So, instead of declaring var name = n;, you would declare this.name = n;. Which would make it look something like
var node = function(n) {
this.name = n;
this.children = [];
this.finished = false;
this.failed = false;
///other functions here
}
I have a Constructor function "Animals", that is namespacing some other Constructor functions, "Crocodile" and "Monkey":
var Monkey = function(Animals) {
this.Animals = Animals;
};
Monkey.prototype.feedMe = function() {
this.Animals.feed();
};
var Crocodile = function(Animals) {
this.Animals = Animals;
};
Crocodile.prototype.feedMe = function() {
this.Animals.feed();
};
var Animals = function(zoo) {
this.zoo = zoo;
};
Animals.prototype.feed = function() {
//feed the animal
};
Animals.prototype.Monkey = function() {
this.Animals = Animals.prototype;
};
Animals.prototype.Monkey.prototype = Monkey.prototype;
Animals.prototype.Crocodile = function() {
this.Animals = Animals.prototype;
};
Animals.prototype.Crocodile.prototype = Crocodile.prototype;
With the intention that I should be able to do the following:
var animals = new Animals("NY");
var monkey = new animals.Monkey();
monkey.feed();
I'm receiving an error that says that monkey.feed() is not a function. I'm assuming i'm doing something wrong with the way i'm inheriting the Monkey function inside the Animal constructor function but for the life of me I haven't been able to find the solution.
What is the correct method I should be using to namespace these functions?
I have seen quite some stuff, but abusing prototypes for namespaces, what the heck. What's wrong with a nice and simple:
var Animals = {
Crocodile: {
}
}
Or if you want the constructor way:
var Animals = function () {
return {
Crocodile: function () {}
}
};
var a = new Animals();
var c = new a.Crocodile();
i'm practicing with Javascript Inheritance, my first try is following code:
var base_class = function()
{
var _data = null;
function _get() {
return _data;
}
this.get = function() {
return _get();
}
this.init = function(data) {
_data = data;
}
}
var new_class = function() {
base_class.call(this);
var _data = 'test';
function _getData() {
return this.get();
}
this.getDataOther = function() {
return _getData();
}
this.getData = function() {
return this.get();
}
this.init(_data);
}
new_class.prototype = base_class.prototype;
var instance = new new_class();
alert(instance.getData());
alert(instance.getDataOther());
to that point i am really happy with my solution, but there is one problem
that i dont get resolved.
the "getDataOther" method don`t return the stored data from the base class,
because i cannot access the public "get" class from the protected "_getData" method in the new_class.
How can i get that running ?
Thanks in advance.
Ps.: Please excuse my poor English
If you comment out the this.init function (which overwrites the base_class _data field) and make the new_class's getData function just return _data, you should be able to get distinct variables.
var base_class = function()
{
var _data = null;
function _get() {
return _data;
}
this.get = function() {
return _get();
}
this.init = function(data) {
_data = data;
}
}
var new_class = function() {
var self = this; //Some browsers require a separate this reference for
//internal functions.
//http://book.mixu.net/ch4.html
base_class.call(this);
var _data = 'test';
function _getData() {
return self.get();
}
this.getDataOther = function() {
return _getData();
}
this.getData = function() {
return _data; //Changed this line to just return data
//Before, it did the same thing as _getData()
}
//this.init(_data); //Commented out this function (it was changing the base_class' data)
}
new_class.prototype = base_class.prototype;
var instance = new new_class();
alert(instance.getData());
alert(instance.getDataOther());
Your english is fine by the way :)