node Javascript class method override - javascript

I have an node library and want to override a method in it but i don't understand how this particular object structure works.
function MyObject(){
this.init();
}
MyObject.prototype.init = function(){
// tons of other stuff
function myMethod(){
// stuff I want to override
}
}
Overriding the init function would be pointless because there is too much stuff in there.
I could just edit the lib but that's dirty and I want to prevent that if possible.
I tired all sorts of stuff but it didn't seem like i got it right.
Is it even possible?

myMethod is a "private" method of the init function, you can't get a reference to it from outside. So if you don't have control over the code defining this (you say you don't want to edit the lib), you can't override the method.

Related

How do I reference the containing class from within a static method when "this" is already taken by the calling object?

Using ES6/ES2015 and webpack, I am trying to wrap my head around the little monster that is the keyword this.
I have a class Edit containing a static method change(event) and within that method I am trying to make a recursive call to the method itself (depending on a given variable).
In most cases I could just call this.change(event) but here the keyword this is already occupied by the jquery object that was calling the function instead of the containing class.
The easiest solution would be to just call Edit.change(event) instead, but there must be a cleaner solution. Every programming language I have encountered so far has had some reference to its containing class built in.
I promise I have checked the docs and other threads on stackoverflow, but no one I found seems to address this particular problem.
// main.js
'use strict';
const $ = require('jquery');
const Edit = require('./Edit');
$(document).ready(() => {
let thingsToAddToData = {
whatToDo: // defined here depending on context
someVariable: //defined here depending on context
};
$('table :input').change(thingsToAddToData, Edit.change);
}
and here the Edit class is defined
// Edit.js
class Edit {
static change(event) {
if(event.data.whatToDo === 'do_nothing'){
return false;
}
if(event.data.whatToDo === 'do_this_important_thing'){
// here some important stuff is done
return true;
}
if(event.data.someVariable === 'special_case'){
event.data.whatToDo = 'do_this_important_thing'
// THIS IS THE LINE THAT GIVES ME HEADACHES
return this.change(event);
}
// here some default stuff is done
}
}
module.exports = Edit;
The easiest solution would be to just call Edit.change(event) instead, but there must be a cleaner solution
No, this is indeed what you need to use to always refer to the Edit class. There's nothing messy with it, just use it.
You could also use this.change(event) if you weren't using the method as an event handler. Make sure to call it as a method:
$('table :input').change(thingsToAddToData, Edit.change.bind(Edit));
// or
$('table :input').change(thingsToAddToData, e => Edit.change(e));
Either of the answers by #Bergi, should work (using Function.prototype.bind or () => {}). However I think your problem is more structural. Since Edit.change is an event handler it doesn't make sense to call it directly, since it is supposed to be fired through events.
I would suggest firing the event again with some parameter changes (http://api.jquery.com/trigger/):
replace Edit.change(event); with this.trigger(event);
That way there is no need for calling the handler directly, and you don't need to change the this context, thus keeping the code more transparent.
Static methods operate on the class instead of instances of the class, they are called on the class. There are two ways to call static methods:
<ClassName>.methodName()
or
<class-instance>.constructor.methodName()
In static methods, the this keyword references the class. You can call a static method from another static method within the same class with this.

$.fn.myPlugin vs $.something.myPlugin in regard to private and public methods

So I can't seem to find astraight answer on this, only vague examples of multiple variations where similar plugin/method declarations are used. I know that by saying
$.fn.myPlugin
I am defining a publicly available plugin method that can be executed on any valid jQuery object where the fn denotes the prototype. My question is then, by defining a method, either inside of my main plugin like so
$.fn.myPlugin.methodName
or outside of my plugin like so
$.something.methodName //where 'something' is in place of 'fn'
does this affect it being a public private/method? and if each is a different type of declaration, what is the difference.
The backstory of why I would like to know, to give some context to the situation, is that I want to define one main plugin that can be called and have run normally, however if the end user wants to redefine some method I have allowed to be public then they can do that. If I have any methods that I don't want the user to redefine but instead provide callbacks so they can hook into it, then I want to make that method private.
Anything set on $.whatever will be public, and therefore able to be modified by other developers.
If you want private methods, you should create a closure.
(function() {
function init(jqObj) { ... } // do magic here
$.fn.myPlugin = function() { init(this); } // avoid exposing core method
$.fn.myPlugin.publicMethod = function() { ... }
function privateMethod() { ... }
})();

Ember.observer run on init

I'm attempting to build an Ember app without prototype extensions and the Ember docs give examples of how to do this, but they don't include the example of when I want my observer to run on init.
So currently if my code were written like this:
fullNameChanged: function() {
// deal with the change
}.observes('fullName').on('init')
The only example I can find to write it is like this:
Person.reopen({
fullNameChanged: Ember.observer('fullName', function() {
// deal with the change
})
});
So how would I tell this code to run on init?
May be you are looking for this
Person.reopen({
fullNameChanged: Ember.on('init', Ember.observer('fullName', function () {
// deal with the change
}))
});
OR (this won't fire handler if change happens on init, use above on that case)
Person.reopen({
init: function(){
Ember.observer('fullName', function() {
// deal with the change
});
}
});
Alright, this edit for answer the mistakes(?) mentioned below
Well, sometimes it might be necessary to fire the observer on initialization time.
Ember.observer is an Ember namespace method, not part of Ember.Object's prototype. Therefore this.observer never exists, but addObserver() does.
There is no need to invoke the handler, Ember runtime will invoke the handler when the property changes
calling this._super is unnecessary unless it really does matter. In this case, if Person just extends Ember.Object calling super doesn't do anything.
By default, does nothing unless it is overridden during class definition.
It's contextual, and as long as OP didn't specify anything about class definition it's beyond the scope of answering.
Nothing better explains than an example
The accepted answer actually contains five separate mistakes, of varying degrees of severity.
It unnecessarily places setting up the observer in the init hook.
It sets up the observer inside the init hook incorrectly, using Ember.observer instead of this.observer, which won't even work.
It fails to invoke (as opposed to setting up) the handler at init time.
It fails to call init on the superclass.
It unnecessarily uses reopen.
1. No need to set up observer in init hook
You do not need any procedural "call" or "invocation" in an init hook to set up an observer. Either of the two following forms will set them up automatically when the object is instantiated.
fullNameChanged: function() { } . observes('fullName')
observeFullNameChanged: Ember.observer('fullName', this.fullNameChanged.bind(this))
2. Use object.observer for procedural setup of observers.
If you did want to set up the observer procedurally, then you call object.observer, not Ember.observer, which is defined for use as above. Calling Ember.observer procedurally will accomplish nothing; Ember will have no idea of what object the property to observe lies. In this case, it would be this.observer('fullName', ...) (although as mentioned above you actually don't need to do this at all; instead use the approach of point 1).
3. Invoke handler on init
But you also want to invoke the handler at init time. There are three ways:
init: function() { this.fullNameChanged(); /* call super */ }
initFullNameChanged: Ember.on('init', this.fullNameChanged.bind(this))
fullNameChanged: function() { ... }.on('init')
where the third option uses the prototype extensions you don't want.
4. Calling super from init
If you are going to have an init hook, even though it's not needed, you need to call super, or things will break down horribly:
init: function() {
...
this._super.apply(this, arguments);
}
5 No need for reopen
reopen accomplishes nothing here. Just put the above properties into the class definition itself.
Solution
The correct answer to what is the equivalent of
fullNameChanged: function observer() { }.observes('fullName').on('init')
is therefore
fullNameChanged: function() { },
observeFullNameChanged: Ember.observer('fullName', this.fullNameChanged.bind(this)),
initFullNameChanged: Ember.on('init', this.fullNameChanged.bind(this))
It would be equivalent, and possibly more readable, to do this:
initFullNameChanged: Ember.on('init', function() {
// define and execute handler
(function fullNameChanged() { ... }());
// set up obsever
this.observe('fullName, fullNameChanged);
})

Calling helper functions from within template.rendered in Meteor.js, error in 1.0, fine in 0.9.3

In an effort to avoid repeating code I found it useful to have helper functions that could be called from within a foo.rendered function (for instance). Why is this possible in 0.9.3 of Meteor, but throws an error in 1.0 ?
Template.foo.helpers({
'fooFn' : function(){
return "something"
}
});
Template.foo.rendered = function(){
var something = Template.foo.fooFn();
}
Should I change the syntax in foo.rendered (am I calling it wrong?) or maybe use a different approach entirely (set up functions outside of the helpers({}) and rendered() and call those? or set this up as a registered helper function?
It looks like it is possible as of Meteor 1.0.3.1 to find and call helper functions, although it is clear it's not supposed to be used like this.
Still it can be done:
Template.foo.__helpers[" fooFn"]()
Please notice the leading space for the function name.
The other way of dealing with this is attaching a function to a global namespace, then calling that from somewhere else in your code, as user3557327 mentioned.
Additionally you can use:
Template.registerHelper('myHelper', function (){return 'Look At Me!'})
to register a global helper, and call it explicitly using:
UI._globalHelpers['myHelper']()
I think this would be a better method: How to use Meteor methods inside of a template helper
Define a function and attach it to the template. Call that function from rendered, as well as your template helper. Like MrMowgli said, you probably aren't "supposed" to call template helpers from within the .js file, only from the ...that could probably break in the future.
For example define a function and attach it to the tamplate:
Template.Play.randomScenario = function () { // HACK HACK HACK }
and then call it from your lifecycle method
Template.Play.created = function () {
Template.Play.randomScenario();
};
scenario: function () {
return Template.Play.randomScenario();;
},
I had the same problem and this is the solution I used. Hope that helps.

Javascript object properties access functions in parent constructor?

So I'm using this pretty standard jquery plugin pattern whereby you can grab an api after applying the jquery function to a specific instance.
This API is essentially a javascript object with a bunch of methods and data.
So I wanted to essentially create some private internal methods for the object only to manipulate data etc, which just doesn't need to be available as part of the API.
So I tried this:
// API returned with new $.TranslationUI(options, container)
$.TranslationUI = function (options, container) {
// private function?
function monkey(){
console.log("blah blah blah");
}
// extend the default settings with the options object passed
this.settings = $.extend({},$.TranslationUI.defaultSettings,options);
// set a reference for the container dom element
this.container = container;
// call the init function
this.init();
};
The problem I'm running into is that init can't call that function "monkey". I'm not understanding the explanation behind why it can't. Is it because init is a prototype method?($.TranslationUI's prototype is extended with a bunch of methods including init elsewhere in the code)
$.extend($.TranslationUI, {
prototype: {
init : function(){
// doesn't work
monkey();
// editing flag
this.editing = false;
// init event delegates here for
// languagepicker
$(this.settings.languageSelector, this.container).bind("click", {self: this}, this.selectLanguage);
}
}
});
Any explanations would be helpful. Would love other thoughts on creating private methods with this model too.
These particular functions don't HAVE to be in prototype, and I don't NEED private methods protected from being used externally, but I want to know how should I have that requirement in the future.
// Edited based on Matthew's comment
So I tried moving the prototype definition based on Matthew's comment. This seems to work now, but still not sure if this is the correct way to be doing this. Thoughts? Obviously it would be cleaner if I move the prototype object into a separate area
$.TranslationUI = function (options, container) {
function monkey(){
console.log("blah blah blah");
}
// extend the default settings with the options object passed
this.settings = $.extend({},$.TranslationUI.defaultSettings,options);
// set a reference for the container dom element
this.container = container;
$.extend($.TranslationUI.prototype,
{
init : function(){
monkey();
// editing flag
this.editing = false;
// init event delegates here for
// languagepicker
$(this.settings.languageSelector, this.container).bind("click", {self: this}, this.selectLanguage);
}
}
);
// call the init function
this.init();
};
So while this works, the crappy part is that I'm re-initing prototype every time that constructor runs. I'm sure that's not efficient. But not sure how else to have the prototype methods have access to private functions/variables of a certain instance.
The error is because monkey is not defined in the scope you're calling $.extend from.
Alright. So found an answer on stackoverflow, confirmed by Crockford's site.
javascript - accessing private member variables from prototype-defined functions
Essentially, you can't really get access to private functions from the prototype methods. You can via 'privileged' functions, which in turn call private variables and functions, but then you are basically creating a crapload of getters and setters, which might just be doubled in your prototype "public" methods.
So its kind of a lot of work, especially if your stuff doesn't TRULY need to be private.
Have a look at my answer and some of the others here:
call function inside a nested jquery plugin

Categories

Resources