Overriding a function on a javascript object's property - javascript

How would you override a function on a javascript object when the function is on another object within the parent object.
Example:
function TestingABC() {
this.events = { finish: function() { console.log("FINISHED"); } };
}
function TestingXYZ() {
TestingABC.call(this);
}
TestingXYZ.prototype = Object.create(TestingABC.prototype);
How would I override the events.finish function on TestingXYZ to run the parent (TestingABC) code along with some new code that I need to write?

Because the events object is property of the instance, not on the prototype, you could employ a technique similar to monkey patching, where you store a reference to the current function, then override the current function with one that can call the old one in addition to doing other stuff.
e.g.
function TestingABC() {
this.events = { finish: function() { console.log("FINISHED"); } };
}
function TestingXYZ() {
TestingABC.call(this);
var superEvents = this.events;
this.events = {
finish: function () {
superEvents.finish();
doMyStuff();
}
};
}
TestingXYZ.prototype = Object.create(TestingABC.prototype);

.events is an instantiated property of the TestingABC() constructor - so you can amend the value once you have an instantiation of it.
Perhaps something like this is what you're after?...
function TestingABC() {
this.events = {
finish: function() {
console.log('ABC FINISHED');
},
other: function() {
console.log('ABC OTHER');
}
};
}
function TestingXYZ() {
TestingABC.call(this);
}
TestingXYZ.prototype = Object.create(TestingABC.prototype);
TestingXYZ.prototype.callEvents = function() {
this.events.finish();
this.events.other();
}
var test1 = new TestingABC();
var test2 = new TestingXYZ();
test2.events.finish = function() {
console.log('XYZ FINISHED');
};
test1.events.finish();
test1.events.other();
//-> ABC FINISHED
//-> ABC OTHER
test2.callEvents();
//-> XYZ FINISHED
//-> ABC OTHER

Related

UnCaught TypeError - Nested objects in Javascript? Why is this not allowed? Object literal notation works

Playing around with some JS tests and I'm trying to instantiate some nested objects in my v namespace. As you'll see below, ClassA and ClassB work as expected. When I try and nest some objects under another property (myCustomProperty) I start running into issues! Could someone explain?
Below is the original code:
var v = (v) ? v : {};
v.someClassA = (function() {
this.hello = function() {
console.log("Class A Hello!");
}
});
v.someClassB = (function() {
this.hello = function() {
console.log("Class B Hello!");
}
});
// this all works!
var myClassA = new v.someClassA();
var myClassB = new v.someClassB();
v.myCustomProperty = (function() {
function someClassC() {
this.hello = function() {
console.log('C');
}
}
function someClassD() {
this.hello = function() {
console.log('D');
}
}
return {
someClassC: someClassC,
someClassD: someClassD
}
});
// Uncaught TypeError: v.myCustomProperty.someClassC is not a function! Why?
var myClassC = new v.myCustomProperty.someClassC();
var myClassD = new v.myCustomProperty.someClassD();
myClassA.hello();
myClassB.hello();
myClassC.hello();
myClassD.hello();
If I change my declaration of v.myCustomProperty to use object literal notation, then it ALL WORKS! :
v.myCustomProperty = {
someClassC: function() {
this.hello = function() {
console.log('C');
}
},
someClassD: function() {
this.hello = function() {
console.log('D');
}
}
}
I guess my question really is how would I make this work using the notation in my original snippet? Possible? Horrible practice to do it that way?
Thanks!
v.myCustomProperty is a function that returns an object. You have to call the function first:
new (v.myCustomProperty().someClassC)();
// ^^
Otherwise, v.myCustomProperty.someClassC() tries to access the property someClassC of the function, and we all know (hopefully) that functions don't have such a property.
Or maybe you intended to execute the function immediately and assign the object to myCustomProperty?
v.myCustomProperty = (function() {
// ...
}()); // <- call function

Check if a private function exists inside an object in JavaScript

How can I check if a private function exist inside an object?
var myObj = function(){
var myFunc = function(){};
var init = function(){
//has myFunc been defined?
}
}
I know that I can do this:
if (typeof myFunc == 'function') {
//myFunc exist
}
But this is checking the global scope.
How can I limit this to my objects scope?
Here is the most simplified case that i need:
var myComponent = function () {
var exportExcel = function () {
};
this.export = function (type) {
if('export'+type is a private function in this scope){
window["export"+type]()//but in local scope;
}
}
};
And here is my work around for now :
var myComponent = function () {
var Exports = {
Excel: function () {
}
};
this.export = function (type) {
if (Exports.hasOwnProperty(type)) {
Exports[type]();
} else {
alert('This Export type has not been implemented Yet ! or it never will ... how knows? well i don\'t ...');
}
}
};
As you probably noticed:
function myFunc () {};
function myObj () {
function init () {
if (myFunc) // passes
};
}
You could cheat a bit :-|
function myObj () {
var isdef = { myFunc: true };
function myFunc () {};
function init () {
if (isdef.myFunc) // do something
};
}
I wonder why one would do that though.
Bases on the extra information given, the most practical pattern is what you're calling the "temporary workaround": keeping your functions in a private object, keyed by type.
var myComponent = function () {
var exporters = Object.create(null, {
"Excel": function () {
// do magic export here
}
});
this.export = function (type) {
if (type in exporters) {
// defined locally
return exporters[type].call(this); // binding is optional
} else {
// no export for you!
}
}
};
This prevents two things:
Referencing the function via string composition,
Querying the global scope (or, actually, any scope in between your component and the global scope).
This may not be your design principle, you could further extend this code to allow for adding / removing exporters.

Accessing a containing object from with in its method?

In the snippet below, an object literal holds properties, one of which is a method that needs access to the the object literal.
However, b.c. it is only used as an event handler callback, this always points to the element that triggered the event.
I need to access the containing object.
Otherwise, I'm forced to put a function in a function which seems odd.
/***************************************************************************************************
**MSimMenu - simple drop down menu
*/
NS.parsel({
Name: 'MSimMenu',
E: {
hold_name: '#hold_name',
wrap_bottom: '#wrap_bottom'
},
A: {
time_out_id: null,
TIME_DELAY: 1000
},
// in mouseout this points to the element that triggered the event
// need access to containing object
mouse_out: function () {
this.A.time_out_id = NS.setTimeout(this.hideBottom, this.A.TIME_DELAY);
},
init: function () {
var self = this;
// tempoaray fix - function in function seems odd
function mouse_out() {
self.A.time_out_id = NS.setTimeout(self.hideBottom, self.A.TIME_DELAY);
}
self.E.hold_name.addEventListener("mouseover", function () {
NS.clearTimeout(self.A.time_out_id);
self.showBottom();
}, false);
self.E.wrap_bottom.addEventListener("mouseover", function () {
NS.clearTimeout(self.A.time_out_id);
}, false);
self.E.wrap_bottom.addEventListener("mouseout", mouse_out, false);
self.E.hold_name.addEventListener("mouseout", mouse_out, false);
},
showBottom: function () {
this.E.wrap_bottom.style.visibility = 'visible';
},
hideBottom: function () {
this.E.wrap_bottom.style.visibility = 'hidden';
}
});
Final Code Using Bind
NS.parsel({
Name: 'MSimMenu',
E: {
hold_name: '#hold_name',
wrap_bottom: '#wrap_bottom'
},
A: {
time_out_id: null,
TIME_DELAY: 1000
},
init: function () {
var self = this;
self.E.hold_name.addEventListener("mouseover", function () {
NS.clearTimeout(self.A.time_out_id);
self.showBottom();
}, false);
self.E.wrap_bottom.addEventListener("mouseover", function () {
NS.clearTimeout(self.A.time_out_id);
}, false);
self.E.wrap_bottom.addEventListener("mouseout", self.mouse_out.bind(self), false);
self.E.hold_name.addEventListener("mouseout", self.mouse_out.bind(self), false);
},
mouse_out: function () {
this.A.time_out_id = NS.setTimeout(this.hideBottom, this.A.TIME_DELAY);
},
showBottom: function () {
this.E.wrap_bottom.style.visibility = 'visible';
},
hideBottom: function () {
this.E.wrap_bottom.style.visibility = 'hidden';
}
});
I have seen alot of people create a variable to assign the object to and then use the variable.
var that = {
myfunc:function(){
console.log(that)
}
};
NS.parsel(that);
I actually like moving most of the logic into the init method. Provides nice encapsulation with an easy way to declare public and private methods/variables. For example:
NS.parsel({
init: function() {
var self = this;
//public instance variable
self.Name = 'MSimMenu';
//private instance variables
var A = {
time_out_id: null,
TIME_DELAY: 1000
};
var E = {
hold_name: '#hold_name',
wrap_bottom: '#wrap_bottom'
};
//public instance method
self.showBottom = function () {
E.wrap_bottom.style.visibility = 'visible';
};
//private instance method
E.wrap_bottom.addEventListener("mouseout", mouse_out, false);
function mouse_out() {
A.time_out_id = NS.setTimeout(self.hideBottom, A.TIME_DELAY);
}
}
});
There's a lot of ways you can get what you want.
One trick you can do is to not use the mouse_out function directly, but provide a helper function like get_mouse_out() that returns a bound version of the function.
var myobject = {
data:"Some data",
_mouse_out: function() { console.log(this.data); }
get_mouse_out: function() {
var self = this;
return function(){ return Function.apply(self._mouse_out,self,arguments); }
}
}
//Example call back using function.
function do_callback(fn) { fn(); }
//This doesn't work.
do_callback( myobject._mouse_out);
//But this does
do_callback( myobject.get_mouse_out() );
EDIT: Improved version inlining _mouse_out and using bind.
var myobject = {
data:"Some data",
get_mouse_out: function() {
function _mouse_out() { console.log(this.data); }
return _mouse_out.bind(this);
}
}
//Example call back using function.
function do_callback(fn) { fn(); }
//But this does
do_callback( myobject.get_mouse_out() );
If you're willing to have init be called as setup before mouse_out is used then you can do this.
var myobject = {
data:"Some data",
init: function() {
function _mouse_out() { console.log(this.data); }
this.mouse_out = _mouse_out.bind(this);
}
}
myobject.init();
fn( myobject.mouse_out );
Finally there's a nice variant on Shanimals that works a similar way, but provides encapsulation.
NS.parcel( (function(){
var myobj = {};
myobj.data = "Some data";
myobj.mouse_out = function(){ console.log(myobj.data); }
return myobj;
})()
);

Minimize object

I have a code like this:
var methods = {
collapse: function(element) {
modify(element);
},
other_method: function() {
// ...
}
};
function modify(element)
{
console.log('collapse method');
}
Is it possible to minify collapse method to one line? So it should always call modify function.
Try this:
var methods = {
collapse: modify,
other_method: function() {
// ...
}
};
function modify(element) {
console.log('collapse method');
}
Because we have function declaration (not expression), modify is visible when you declare the object methods. The thing which is done here is just setting collapse to be equal to modify's reference.
This is the same as:
var modify = function (element) {
console.log('collapse method');
}
var methods = {
other_method: function() {
// ...
}
};
methods.collapse = modify;

access parent object in javascript

var user = {
Name: "Some user",
Methods: {
ShowGreetings: function() {
// at this point i want to access variable "Name",
//i dont want to use user.Name
// **please suggest me how??**
},
GetUserName: function() { }
}
}
You can't.
There is no upwards relationship in JavaScript.
Take for example:
var foo = {
bar: [1,2,3]
}
var baz = {};
baz.bar = foo.bar;
The single array object now has two "parents".
What you could do is something like:
var User = function User(name) {
this.name = name;
};
User.prototype = {};
User.prototype.ShowGreetings = function () {
alert(this.name);
};
var user = new User('For Example');
user.ShowGreetings();
var user = {
Name: "Some user",
Methods: {
ShowGreetings: function() {
alert(this.Parent.Name); // "this" is the Methods object
},
GetUserName: function() { }
},
Init: function() {
this.Methods.Parent = this; // it allows the Methods object to know who its Parent is
delete this.Init; // if you don't need the Init method anymore after the you instanced the object you can remove it
return this; // it gives back the object itself to instance it
}
}.Init();
Crockford:
"A privileged method is able to access the private variables and
methods, and is itself accessible to the public methods and the
outside"
For example:
function user(name) {
var username = name;
this.showGreetings = function()
{
alert(username);
}
}
You can try another approach using a closure:
function userFn(name){
return {
Methods: {
ShowGreetings: function() {
alert(name);
}
}
}
}
var user = new userFn('some user');
user.Methods.ShowGreetings();
Old question but why can't you just do something like this :
var user = {
Name: "Some user",
Methods: {
ShowGreetings: function() {
// at this point i want to access variable "Name",
//i dont want to use user.Name
// **please suggest me how??**
var thisName = user.Name; //<<<<<<<<<
},
GetUserName: function() { }
}
}
Because you will only call user.Methods.ShowGreetings() after the user has been instantiated. So you will know about the variable 'user' when you want to use its name ?
As others have said, with a plain object it is not possible to lookup a parent from a nested child.
However, it is possible if you employ recursive ES6 Proxies as helpers.
I've written a library called ObservableSlim that, among other things, allows you to traverse up from a child object to the parent.
Here's a simple example (jsFiddle demo):
var test = {"hello":{"foo":{"bar":"world"}}};
var proxy = ObservableSlim.create(test, true, function() { return false });
function traverseUp(childObj) {
console.log(JSON.stringify(childObj.__getParent())); // returns test.hello: {"foo":{"bar":"world"}}
console.log(childObj.__getParent(2)); // attempts to traverse up two levels, returns undefined because test.hello does not have a parent object
};
traverseUp(proxy.hello.foo);
Very late to the party, but this works
var user = {
Name: "Some user",
Methods() {
return {
that: this,
ShowGreetings: function() {
console.log(this.that.Name)
},
GetUserName: function() { }
}
}
}
user.Methods().ShowGreetings() // Some user
David Dorward's right here. The easiest solution, tho, would be to access user.Name, since user is effectively a singleton.
ES6 Classes
One simple solution would be to create a Class with methods!
class User {
// Assign properties when an instance
// is created using the `new` keyword
constructor(name) {
this.name = name;
}
// Methods:
showGreetings() {
console.log(`Hello, ${this.name}!`);
}
getUserName() {
return this.name;
}
// Or rather, use Getters:
get username() {
return this.name;
}
}
// Create a new user:
const user = new User("Praveen");
// Use methods:
user.showGreetings(); // "Hello, Praveen!"
console.log(user.getUserName()); // "Praveen"
console.log(user.username); // "Praveen"
Why the above suggestion? Mostly because:
you cannot reference a parent Object from a child Object directly
const User = {
name: "Some user", // hardcoded stuff? Is this an intentional Singleton?
methods: { // <<< Child Object of User
sayName() {
// Sadly, `this` refers to `methods`, not to `user`:
console.log(this); // methods{}
console.log(User.name); // "Some user" // Get Singleton's name
// ... but that's not what you want.
}
}
};
User.methods.sayName();
// ^^^^^^^ Why would you want this `methods` anyways?!
and it makes no sense to hardcode Strings (like "Some user") inside an Object Singleton — which could actually be a reusable function Object.
If you want to associate a child Node to a parent Node — read this answer (Get value of parent Object).
How about this way?
user.Methods.ShowGreetings.call(user, args);
So you can access user.Name in ShowGreetings
var user = {
Name: "Some user",
Methods: {
ShowGreetings: function(arg) {
console.log(arg, this.Name);
},
GetUserName: function() { }
},
Init: function() {
this.Methods.ShowGreetings.call(this, 1);
}
};
user.Init(); // => 1 "Some user"
As a variant:
var user = (obj => {
Object.keys(obj.Methods).map(option => {
const currOpt = obj.Methods[option];
if (currOpt instanceof Function) {
obj.Methods[option] = currOpt.bind(obj);
};
});
return obj;
})({
Name: "Some user",
Methods: {
Greeting: function () { return this.Name },
GetUserName: function() { console.log(this) }
},
});
But I don't know why somebody can use this strange approach
I know I'm very late.
I wrote this simple method. Let's say you have:
{
subObj: {
x:'hello_world';
}
}
Then, if you want a reference to the bigger object from subObj, you can convert it to a function, and utilize this.
var tmpVal=reference_to_subObj; //keep value of subObj safe
reference_to_subObj=function(){return this;}//this returns the scope, here the parent
var parent=reference_to_subObj(); //call the function
reference_to_subObj=tmpVal; delete tmpVal; //set things back to normal
//Now you have variable 'parent'.
I used a Function() constructor because it let me create the function as a string, so I could pass a string as code.
function findParent(stringReference) {
Function(/*same as above, except filled in all reference_to_subObj with stringReference.*/
//stringReference is a stringified version of dot or bracket notation.
So I could call findParent('obj.subObj').
// Make user global
window.user = {
name: "Some user",
methods: {
showGreetings: function () {
window.alert("Hello " + this.getUserName());
},
getUserName: function () {
return this.getParent().name;
}
}
};
// Add some JavaScript magic
(function () {
var makeClass = function (className) {
createClass.call(this, className);
for (key in this[className]) {
if (typeof this[className][key] === "object") {
makeClass.call(this[className], key);
}
}
}
var createClass = function (className) {
// private
var _parent = this;
var _namespace = className;
// public
this[className] = this[className] || {};
this[className].getType = function () {
var o = this,
ret = "";
while (typeof o.getParent === "function") {
ret = o.getNamespace() + (ret.length === 0 ? "" : ".") + ret;
o = o.getParent();
}
return ret;
};
this[className].getParent = function () {
return _parent;
};
this[className].getNamespace = function () {
return _namespace;
}
};
makeClass.call(window, "user");
})();
user.methods.showGreetings();
I ran across this old post trying to remember how to solve the problem. Here is the solution I used. This is derived from Pro JavaScript Design Patterns by Harmes and Diaz (Apress 2008) on page 8. You need to declare a function and then create a new instance of it as shown below. Notice the Store method can access "this".
function Test() {
this.x = 1;
}
Test.prototype = {
Store: function (y) { this.x = y; },
}
var t1 = new Test();
var t2 = new Test();
t1.Store(3);
t2.Store(5);
console.log(t1);
console.log(t2);
Like #Quentin said, there is no upwards relationship in JS. However try this workaround;
foo = { bar: {parent: foo} };
console.log(foo);
console.log(foo.bar.parent);
which is also similar to;
function Foo(){
this.bar = {parent: this}
}
foo = new Foo();
console.log(foo);
console.log(foo.bar.parent);

Categories

Resources