javascript: class method access deep function - javascript

Is it possible to access method/function m1 from instance of MyObjGraph?
Thanks in advance for your answers
class MyObjGraph
{
constructor(id)
{
this.drawGraph(id);
}
drawGraph(id)
{
var inId = id;
function m1()
{
alert(inId);
}
}
}

Nope, because it is considered as local function so the scope wouldn't be outside the drawGraph method. Only drawGraph method can access it.

If you can slightly modify the code, you could expose the inner method to the "outside":
class MyObjGraph {
constructor(id) {
this.drawGraph(id);
}
drawGraph(id){
var inId = id;
function m1(){
alert(inId);
}
return { // <-------- return an object of everything you want to be exposed
m1
}
}
}
const instance = new MyObjGraph();
instance.drawGraph("123").m1()
Explanation:
In your original code, the method drawGraph does not return anything, therefor it only executes code, and nothing inside of it is accessible.
For anything to be accessible directly from a function, the function needs to have a return statement, so when you invoke that function you get something in "return"... and that something, in this case below, is an Object with a single property: m1 (reference to the m1 inner function)

Related

Is it possible to append a method to a constructor/function without prototype property?

function DoIHavePrototype()
{
var a = 10;
}
CheckIt = new DoIHavePrototype();
DoIHavePrototype.prototype.GetFnName = function()
{
return "DoIHavePrototype"
}
alert(CheckIt.GetFnName())
In the above code,I observe that prototype is an in-built property for the function using which we can append property/method to a function.
But if I remove the prototype keyword in the above code like the following:
DoIHavePrototype.GetFnName = function()
{
return "DoIHavePrototype"
}
I don't get error in function definition but instead I get error while calling the method
alert(CheckIt.GetFnName()) as "CheckIt.GetFnName is not a function"
What does the JS interpreter assume this to be??
In order to be able to invoke some function a method on an object, there are 4 ways to introduce it to the object.
The first way is what you've done in your original code, which is to assign the function to the object prototype:
Foo.prototype.myFunc = function () { .... }
Another way is to assign it to this within the constructor.
function Foo() {
this.myFunc = function () { .... }
}
We can also assign it directly to the instance:
var foo = new Foo();
var myFunc = function () { .... }
foo.myFunc = myFunc
Finally, we can bind a function to the instance:
var foo = new Foo();
var myFunc = function () { .... }
var myFuncFoo = myFunc.bind(foo)
The last case is a bit special since we have a function that's not a property of the instance, but behaves like an instance method because it's invocation context is affixed to the instance.
The most common way of defining instance methods is assignment to the prototype. The prototype property on the constructor is what the instances inherit from, so that's where we put stuff. It's important to keep in mind that the instances inherit from the prototype property, not the constructor function. Assigning anything to a constructor property does not make it available as an instance property.
Assignment to this can sometimes be used if we want to have a method that's bound. For instance:
function Foo() {
this.boundMeth = this.meth.bind(this)
this.val = "foo"
}
Foo.prototype.meth = function () {
console.log(this.val)
}
This is useful if we want to pass instance.boundMeth() as a value to another function (e.g., event handler). In JavaScript, unlike many OO languages, methods are unbound:
// Using Foo from the previous example
function runner(fn) {
fn()
}
var obj = new Foo()
runner(obj.meth) // Logs `undefined`
runner(obj.boundMeth) // Logs `foo`
When assigning to the constructor prototype, you can assign in bulk:
Foo.prototype = {
meth1: function () { .... },
meth2: function () { .... },
}
If you use ES6, you can also use the class keyword:
class Foo {
myFunc() { .... }
}
This is the same as Foo.prototype.myFunc = function () { .... }.
If you append your function straight to the class it will generate so called static method which you can only call from you class like in Array.from.
So in your case you should call it using you class (not its instances) like so DoIHavePrototype.GetFnName();
you can read about this on MDN
This can also be done, in case if you still want to use it as instance method.
function DoIHavePrototype()
{
var a = 10;
this.GetFnName = function() {
return "DoIHavePrototype";
}
}
CheckIt = new DoIHavePrototype();
alert(CheckIt.GetFnName())

Third party library is binding callbacks, but I need to access class properties

I've seen several questions about using "this" in classes and functions, but I don't think I've seen what I'm looking for in particular.
My situation is:
I'm calling a function from a third-party library in a class method. However, the third-party library function is calling callback.bind(this), and I need to have access to the context it's binding.
But I also want to be able to access class properties. Is this possible?
If not, what are some potential workaround? Code outline looks something like:
class MyClass {
myProperty = 'something';
myMethod() {
console.log(this.myProperty);
}
otherMethod() {
thirdPartyLibrary.functionRequiringCallback(function() {
this.MyMethod(); //undefined
this.requiredThirdPartyFunction(); //"this" refers to thirdPartyLibrary
});
}
}
I could certainly make the callback an arrow function so that "this" refers to the class-scope, but then I won't have access to "requiredThirdPartyFunction".
Any help would be appreciated.
When you want a reference to your instance this, you can always use the old that = this assignment. You assign this to a variable in the scope (that usually), and then you can reference it inside the callback.
otherMethod() {
const that = this; // set a reference to the instance this
thirdPartyLibrary.functionRequiringCallback(function() {
that.MyMethod(); // that refers to your class instance this
this.requiredThirdPartyFunction(); //"this" refers to thirdPartyLibrary
});
}
Another option is to bind myMethod, by using an arrow function or Function#bind, and then assign the bound method to a variable:
class MyClass {
myProperty = 'something';
myMethod = () => console.log(this.myProperty);
otherMethod() {
const myMethod = this.myMethod; // assign the bound method to a variable
thirdPartyLibrary.functionRequiringCallback(function() {
MyMethod(); // will be invoked with original this
this.requiredThirdPartyFunction(); //"this" refers to thirdPartyLibrary
});
}
}
There are not so many options here. Since there is only one this, it can be either lexical:
otherMethod() {
thirdPartyLibrary.functionRequiringCallback(() => {
this.MyMethod();
thirdPartyLibrary.requiredThirdPartyFunction();
});
}
Or dynamic:
otherMethod() {
const _this = this;
thirdPartyLibrary.functionRequiringCallback(function() {
_this.MyMethod();
this.requiredThirdPartyFunction();
});
}
The first option is more readable and is likely a better choice, since it's not obvious from the code above that this === thirdPartyLibrary inside callback.

Closures Cannot access a function

I am trying to understand closures. In the code below, I create an instance of the constructor function Ninja and I call the instance kawazaki. I expected to be able to access the methods of Ninja. However, I am getting a TypeError: Object #<Ninja> has no method 'feints' instead.
The output I expected was 1.
Here is my code:
function Ninja() {
var feints = 0;
function getFeints() {
return feints;
}
function feints() {
feints++;
}
}
var kawazaki = new Ninja();
kawazaki.feints();
console.log(kawazaki.getFeints());
Try this instead:
var kawazaki = new Ninja;
kawazaki.feints();
alert(kawazaki.getFeints());
function Ninja() {
var feints = 0;
this.getFeints = function () {
return feints;
};
this.feints = function () {
feints++;
};
}
You need to assing public properties to this within the constructor function.
The scope of the functions getFeints and feints is limited to the function Nija. As you can not access to variables declared in a function, you can not access to those functions.
To be able to execute kawazaki.feints(), you have to "attach" the function to the Ninja function, as an object (which a function also is)
You will find in these resources several ways to achieve that, and also some deeper explanations:
How do JavaScript closures work?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
Closure is a very simple yet largely misunderstood topic.
function Ninja() {
var feints = 0;
function getFeints() {
return feints;
}
function feintsInc() {
feints++;
}
}
You have defined the closure alright but please note that a closure is not actually a method of the object. In order to get your desired output you need to call the closures just before closing the object.
feintsInc();
getFeints();
If,however, you wish to do it as
kawazaki.feintsInc();
you need to use this keywords in your function to get the functions assigned to the object.
Note,make sure your functions and variable names don't overlap.

Namespace issue in javascript

The function name is mixed even if I am using a namespace. In the below example when I call nwFunc.callMe() or $.Test1.callTest() it will execute _testFunction() of doOneThing. I am expected for $.Test1.callTest() to call _testFunction() in $.Test1 API instead of one in doOneThing. What I need to do to correct it?
Example:
var doOneThing = function() {
_testFunction= function() {
...
}
return {
// public
callMe: function(){
_testFunction();
}
}
}
var nwFunc = doOneThing();
nwFunc.callMe();
$.Test1.callTest();
below is a example API
jQuery.Test1 = (function(){
_testFunction= function() {
...// do differently
}
return {
// public
callTest: function(){
_testFunction()
}
}
}(jQuery))
You're not in an object literal, you are in a function body.
_testFunction: function() {
.... // do differently
}
is not an object property, but an anonymous function expression preceded by a label and is immidiately forgotten as it is not assigned anywhere. Make it a simple function declaration instead:
function _testFunction() {
.... // do differently
}
And
return {
// public
callMe() {
_testFunction();
}
}
is just a syntax error, in here you need the object literal sytnax:
return {
// public
callTest: function() {
_testFunction()
}
};
or
return {
// public
callTest: _testFunction // exporting the function directly
};
When I call nwFunc.callMe() or $.Test1.callTest() it will execute _testFunction() of doOneThing. What I need to do to correct it?
You have to use a var declaration to put your _testFunction variable in a local scope. Currently you're writing to the global scope, where only one _testFunction exists (currently in doOneThing you're overwriting the _testFunction from jQuery.Test1, and both callTest functions will invoke the new one). A function declaration would've fixed this as well (using the local scope), it is similar to a var statement + function expression.
You are mixing up your syntax slightly. You are using object literal notation when you declare the function originally and using function declaration notation when actually creating the object, so you should switch the two:
jQuery.Test1 = (function(){
function _testFunction() {
.... // do differently
}
return {
// public
callTest: _testFunction
}
}(jQuery))

Javascript public variable/methods

I have JavaScript code as below;
var foo = (function() {
//Private vars
var a = 1;
return {
//Public vars/methods
a: a,
changeVar: function () {
a = 2;
}
}
})();
Now I am not sure how the syntax for public vars/methods works ?
Could you please corelate how just "returning" the vars/methods makes them as public ?
Thank you.
The value of the variable foo is actually the value returned by this function. Notice on the last line, the (), indicating that this function is evaluated immediately. By evaluating a function and assigning its return value to a variable, you are able to hide variables inside a local (function) scope, such that they are not accessible outside that scope. Only members on the returned object are accessible, but because any functions inside form a closure with their outer scope, you can still use local (hidden) variables.
An example of this would be to hide some local state and only allow access to it through a method:
var foo = (function() {
//Private vars
var a = 1;
return {
//Public methods
getVar: function () {
return a;
},
setVar: function (val) {
a = val;
}
}
})();
Okay, you've returned an object in the anonymous function, which means that the object is assigned to foo. So you can access the object's properties like foo.a or foo.changeVar, but you can continue to let the private variables exist, within the function's scope. Can't help much without a more specific question.

Categories