I was trying to implement an interface like architecture in JS as followed in C#. And met with a stumbling block. Here is the code sample:
// Interface for UIBuilder classes
function IUIBuilder() {
this.addUserToList = function () {
alert('parent: added');
};
}
// Class implementing the IUIBuilder
function ChatUIBuider() {
IUIBuilder.prototype.addUserToList = function () {
alert('child: added');
};
IUIBuilder.prototype.removeUserFromList = function () {
alert('child: removed');
};
return new IUIBuilder();
}
In the first class, I've defined a method addUserToList which I override in the second class ChatUIBuider. Also added one more method removeUserFromList to the base class using its prototype.
My issue is, the addUserToList method still invokes the parent class method even after it has got overridden in the child class. Why?
var builder = new ChatUIBuider();
builder.removeUserFromList(); // Invokes the child class method. - CORRECT
builder.addUserToList(); // Invokes the base class method- WHY??
Could anyone tell me if this is the correct way I am doing?
I suggest this construct :
function IUIBuilder() {
};
IUIBuilder.prototype.addUserToList = function () {
alert('parent: added');
};
// Class extending the IUIBuilder
function ChatUIBuider() {
}
ChatUIBuider.prototype = new IUIBuilder();
ChatUIBuider.prototype.addUserToList = function () {
alert('child: added');
};
ChatUIBuider.prototype.removeUserFromList = function () {
alert('child: removed');
};
ChatUIBuider extends IUIBuilder and inherits its functions but overrides the addUserToList function.
In the following code, both constructors will be called but only the overriding addUserToList function will be called :
var chat = new ChatUIBuider();
chat.addUserToList();
See demonstration
#Denys restructured the entire code , without exactly pointing out the issue. issue is addUserToList is not a prototype method of your parent class , it's a this method which is copied for every instance and not sahred. So just converting it to a prototype method fixes the issue.
// Interface for UIBuilder classes
function IUIBuilder() {
}
IUIBuilder.prototype.addUserToList = function () {
alert('parent: added');
};
// Class implementing the IUIBuilder
function ChatUIBuider() {
IUIBuilder.prototype.addUserToList = function () {
alert('child: added');
};
IUIBuilder.prototype.removeUserFromList = function () {
alert('child: removed');
};
return new IUIBuilder();
}
var builder = new ChatUIBuider();
builder.removeUserFromList(); // Invokes the child class method. - CORRECT
builder.addUserToList(); // Invokes the CHILD CLASS's METHOD
Related
class Test {
DISPATCH_TABLE = {
"Outer Method": this.outerMethod
}
innerMethod() {
console.log("success");
}
outerMethod() {
console.log(this);
this.innerMethod();
}
dispatch(method_name) {
this.DISPATCH_TABLE[method_name]()
}
constructor() {
this.outerMethod = this.outerMethod.bind(this)
}
}
t = new Test()
t.dispatch("Outer Method")
This logs the dispatch table itself and then prints the error, "this.innerMethod is not a function". I understand why this would be bound to the dispatch table without the bind() call in the constructor, but I thought that including that call was supposed to force this to refer to the class in any calls to the bound method.
I'm not blaming JavaScript or bind() for my expectation. I just don't know why my expectation is wrong.
I could just use a switch statement instead of a dispatch table, but I'd prefer to use a dispatch table if I can.
You'll probably have a better time using arrow functions, which are always correctly this-bound.
I took the liberty of changing your dispatch table to map "verbose names" of function to internal method names, too.
class Test {
DISPATCH_TABLE = {
"Outer Method": "outerMethod",
};
innerMethod = () => {
console.log("success");
};
outerMethod = () => {
console.log(this);
this.innerMethod();
};
dispatch(method_name) {
const meth = this[this.DISPATCH_TABLE[method_name]];
if (!meth) throw new Error(`no such method ${meth}`);
return meth();
}
}
t = new Test();
t.dispatch("Outer Method");
I currently have the following working code:
Function.prototype.GetLastCallerName = function () {
if (!this.arguments || !this.arguments.callee || !this.arguments.callee.caller) return null;
var result = /^function\s+([\w\$]+)\s*\(/.exec(this.arguments.callee.caller.toString());
this.LastCaller = result ? result[1] : 'Anonymous';
return this.LastCaller;
};
I picked up that code from another thread. As you can see, it extends the Function.prototype in order to add a method called GetLastCallerName, which picks the last calling function name and (1) sets it to LastCaller on Function.LastCaller and (2) returns it.
In order to make it work:
function MyFunction1() {
MyFunction1.GetLastCallerName();
console.log(MyFunction.LastCaller);
}
function MyFunction2() {
MyFunction1();
}
MyFunction2();
What I'd like to be able to do: Eliminate the need to use GetLastCallerName() every time and extend Function in order to perform that get every time any function is called.
I'm struggling to follow what you have tried so far with your example, but I think I get the idea of what you'd like to do. Why not leverage classes, and extend on them for your use case. Check out the following example...
class Base {
baseFn() {
console.log('from base');
}
}
class Thing extends Base {
fn1() {
this.baseFn();
}
}
let thingee = new Thing();
thingee.fn1();
So baseFn is now always called when fn1 is called.
JSFiddle Link - class demo
In some of your comments it looks like you are wanting to get the "last calling function's name." How about passing back the instance of the caller itself to the parent? This would surely give you even more flexibility because now you can sculpt your caller however you wish. Check out the following...
class Base {
baseFn(caller) {
console.log(caller.id); // 1
}
}
class Thing extends Base {
constructor(id) {
super();
this.id = id;
}
fn1() {
this.baseFn(this);
}
}
let thingee = new Thing('1');
thingee.fn1();
Now you can add whatever you'd like to your Thing instance, in this case, an object with an id of 1 which can be inspected when fn1 propagates up to baseFn
JSFiddle Link - caller demo
I try to change some way to call methods into namespace.
Calling parent methods (I dont think its possible)
Creating and call inheritance function
Calling inside another method (mostly jquery onReady event function) (this.MyFunction() not working)
I split every namespace in files (want to keep it that way)
I try How to call function A from function B within the same namespace? but I didn't succed to split namespaces.
my fiddle sample got only 1 sub-namespace but could be more.
https://jsfiddle.net/forX/kv1w2rvc/
/**************************************************************************
// FILE Master.js
***************************************************************************/
if (!Master) var Master = {};
Master.Print= function(text){
console.log("master.Print :" + text);
$("body").append("<div>master.Print : " + text + "</div>");
}
/**************************************************************************
// FILE Master.Test1.js
***************************************************************************/
if (!Master) var Master = {};
if (!Master.Test1) Master.Test1 = {};
/**************************************************************************
* Descrition :
* Function for managing event load/documentReady
**************************************************************************/
Master.Test1.onReady = function () {
$(function () {
Master.Test1.Function1(); //try to replace because need all namespace.
try {
this.Function2(); //not working
}
catch(err) {
console.log("this.Function2 not working");
$("body").append("<div>this.Function2 not working</div>");
}
try {
this.Print("onReady"); //not working
}
catch(err) {
console.log("this.Print not working");
$("body").append("<div>this.Print not working</div>");
}
try {
Print("onReady"); //not working
}
catch(err) {
console.log("Print not working");
$("body").append("<div>Print not working</div>");
}
});
}
Master.Test1.Function1 = function () {
console.log("Function1");
$("body").append("<div>Function1</div>");
this.Function3(); //working because not inside another function
}
Master.Test1.Function2 = function () {
$("body").append("<div>Function2</div>");
console.log("Function2");
}
Master.Test1.Function3 = function () {
$("body").append("<div>Function3</div>");
console.log("Function3");
Master.Print("Function3"); //try to replace because need all namespace.
}
Master.Test1.onReady();
I use Master.Test1.Function1(); and I want to change that because Function1 is inside the same namespace.
I use Master.Print("Function3"); I dont think I can change that. the way I try to use it, it's more an inheritance function. but I dont know if theres a way to do that?
Maybe I should change the my namespace methode? maybe prototype will do what I want?
You can capture the this in a variable because this inside $(function() {}) will point to document object. The below will work provided you never change the calling context of onReady -- i.e. it is always called on the Test1 object and not called on other context:
Master.Test1.onReady = function () {
var self = this;
$(function () {
self.Function1();
// ..
});
}
To access Print you have to reference using the Master object like: Master.Print() as it won't be available in the Test1 object
this is document within .ready() or jQuery() alias for .ready() where function(){} is parameter $(function() {}). this at this.Function2() will reference document.
"Objects" in javascript are not built the same way as in most object-oriented languages. Essentially, what you are building is a hierarchy of static methods that have no real internal state in-and-of themselves. Therefore, when one of the defined methods is invoked, the context (or state) of that method depends on what object invoked the method.
If you want to have any internal context, you will need to create an "instance" of an "object prototype". At that point, you can use "this.otherFunction" within your other functions. Here is a small example:
var MyObject = function() {};
MyObject.functionOne = function() {
console.log("Function 1");
this.functionTwo();
};
MyObject.functionTwo = function() {
console.log("Function 2");
};
var instanceOne = new MyObject();
instanceOne.functionOne();
You might get some more information about object definition here
I am trying to come up with a page on which, when user clicks a file button on the page, I try to execute the JS on the page. And I am trying to use OOP / class so hopefully it can be reused later. Here is my test code:
// This is the "class".
function BearUpload() {
// some values will go here...
}
// Add a few functions
BearUpload.prototype.function1 = function () {
console.log("function1 called");
}
BearUpload.prototype.handleFileSelect = function (evt) {
console.log("handleFileSelect called");
this.function1();
}
var myBear = new BearUpload(); // Create a global variable for the test
$(document).ready(function () {
var some_condition_goes_here = true;
if (some_condition_goes_here) {
$("#my-file-select-button").change(myBear.handleFileSelect);
}
});
However, it gets error like:
TypeError: this.function1 is not a function
this.function1();
Any idea about this?
Thanks!
Bind myBear to your change eventListener
In general when you access this from handleFileSelect, this refers to the html element.
i.e. this = <input type="file" id="my-file-select-button">
$("#my-file-select-button").change(myBear.handleFileSelect.bind(myBear));
The bind() method creates a new function that, when called, has its
this keyword set to the provided value, with a given sequence of
arguments preceding any provided when the new function is called.
MDN doc
You are trying to call function1 on DOM object but you have to call on jQuery object
$(this).function1();
That's because when bound as a handler to jQuery events, this would refer to the element on which the event is triggered.
I would rather change your code like this
// Create only one global variable for your app
var APP = {};
// Create class using immediate function/closure
APP.BearUpload = (function(){
//declare private variables here
// Constructor
var bearUpload = function() {
// some values will go here...
}
// Add a few functions
bearUpload.prototype.function1 = function () {
console.log("function1 called");
}
bearUpload.prototype.handleFileSelect = function (evt) {
console.log("handleFileSelect called");
this.function1();
}
return bearUpload;
}());
APP.myBear = new APP.BearUpload();
$(document).ready(function () {
var some_condition_goes_here = true;
if (some_condition_goes_here) {
$("#my-file-select-button").change(function(e){
// do something with event 'e'
APP.myBear.handleFileSelect.call(APP.myBear, e);
});
}
});
do not use "this", it is confusing some time.
BearUpload.prototype ={
function1:function(){
var self = this;
...
},
handleFileSelect:function(e){
var self = this;
...
}
}
I've got some code in JavaScript and I'm looking to trigger a ViewModel method using a keyboard shortcut. What is the correct syntax? Here's my code:
document.addEventListener('keydown', function(event) {
if (event.keyCode==27){
ViewModel.escapePressed();
}
}, true);
function ViewModel() {
this.escapePressed=function(){
// Code
};
}
If you are going to use that style of class, then you must first make an instance of it.
var a_view_model = new ViewModel();
a_view_model.escapePressed();
… but if you just want to have a static method, then you probably shouldn't be using a constructor function in the first place
var view_model = {
escapePressed: function () { };
}
and:
view_mode.escapePressed();