How can I run function automatically when calling object at each time? - javascript

How can I run function automatically when calling object at each time ?
I have the following object :
var myObject = {
main: function(e) {
//main
},
x: 1,
y: 2,
another: function(e) {
//another
}
}
Is it possible to achieve the below functionality?
Calling
myObject();
would call the main method.
But calling
myObject().another();
Would call the another method.
use only myObecjt() not myObecjt.main()

If I understood the question correctly, the code structure you're looking for is as follows:
var myObject = (function () {
var t = {};
t.main = function() {
console.log("main");
};
t.another = function () {
console.log("another");
};
t.main();
return t;
});
This will result in the following functionality:
Calling myObject(); will call the main method.
Calling myObject().another(); will call both the main and another methods.

if you are looking for jquery like chaining try something like this
function myObject(){
if(this == window){
return new myObject();
}
//whatever the main method does
return this;
}
myObject.prototype.x = 1;
myObject.prototype.y = 2;
myObject.prototype.another = function(){
//whatever the another method does
return this;
}
something like this, would recommend to investigate method chaining and prototypal inheritance, for a clean aplication of this.
or for something more simple
function myObject(){
//whatever the main method does
return myObject;
}
myObject.x = 1;
myObject.y = 2;
myObject.another = function(){
//whatever the another method does
return myObject;//method chaining may continue
}

Related

Calling a JavaScript function from a nested objects function fails

On the simple example below and on JSFiddle here - https://jsfiddle.net/jasondavis/dnLzytju/ you can see the issue I have.
I can see why it could happen but I am not sure how to fix it while keeping the same JS structure.
The issue is when I define a JavaScript objects prototype functions and I have a 2nd level nested object which has a function and in that function I call a function on the parent/root level it fails.
This function from the code below this.nestedObject.nested_object_function() tries to call the function this.normal_function() however it fails and says:
Uncaught TypeError: this.normal_function is not a function
at Object.nested_object_function (VM2493:79)
I assume the reason is that this is referencing this.nestedObject instead of the parent object.
If that is the case, then how can I call that function like I am trying to do from the nested object function and call a parent function?
I have also tried calling JsLibTest.normal_function() as a test from the this.nestedObject.nested_object_function() function but I get the same error.
var JsLibTest = (function (document) {
"use strict";
var JsLibTest = function (){
// run init() function on initiation of a new JsLibTest object
this.init();
};
/**
* JsLibTest prototype functions
*/
JsLibTest.prototype = {
init: function() {
// as expected this function runs fine
this.normal_function();
// nested level objects functions run fune from parent level object function
this.nestedObject.nested_object_function();
},
normal_function: function() {
console.log('this.normal_function() ran');
},
nestedObject: {
// calling a function on the parent object fails here when called from this nested object function
nested_object_function: function() {
this.normal_function();
console.log('this.nestedObject.nested_object_function() ran');
},
}
};
return JsLibTest;
})(document);
// run it
$(document).ready(function(){
var Sidebar2 = new JsLibTest();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Your assessment is correct. this will be set to the nested object instead of the parent object and that's why it says the function is undefined.
What you need is a way of referencing the parent. Objects don't normally carry any information needed to reference an object which references them. This makes sense when you consider the fact that many objects can reference the same object internally.
You can either store a reference to the parent object and reference that in the nested function:
var nested = {
g() {
this.parent.f();
}
};
var parent = {
f() {
console.log('called');
}
};
nested.parent = parent;
nested.g();
or you can use Function.prototype.call (or something similar) to set the correct context.
var obj = {
f() {
console.log('called');
},
g() {
this.nested.nested_f.call(this);
},
nested: {
nested_f() {
this.f();
}
}
};
obj.g();
Putting the last solution in to the context of your problem:
var JsLibTest = (function(document) {
"use strict";
var JsLibTest = function() {
this.init();
};
JsLibTest.prototype = {
init: function() {
this.normal_function();
// NOTICE: Using .call here to set the context
this.nestedObject.nested_object_function.call(this);
},
normal_function: function() {
console.log('this.normal_function() ran');
},
nestedObject: {
nested_object_function: function() {
this.normal_function();
console.log('this.nestedObject.nested_object_function() ran');
}
}
};
return JsLibTest;
})(document);
// run it
$(document).ready(function() {
var Sidebar2 = new JsLibTest();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You are correct that scope doesn't have access to the parent. Easy solution would be that you pass parent to the nested object like:
this.nestedObject.nested_object_function(this);
then in your nested function call parent as:
nested_object_function: function(self) {
self.normal_function();
alert('this.nestedObject.nested_object_function() ran');
}
since you pass this (parent) as self you can then call it from nested one.
At first, the Object must be unique for Each, having a prototype:
this.nestedObject=Object.create(this.nestedObject);
var JsLibTest = function (){
// run init() function on initiation of a new JsLibTest object
this.init();
//bind to childs:
this.nestedObject.parent=this;
};
Now you can use this.parent inside of your inner function...
this.parent.normal_function();
If you want this to be the parent, bind:
var JsLibTest = function (){
// run init() function on initiation of a new JsLibTest object
this.init();
//bind to childs:
for(i in this.nestedObject){
var el=this.nestedObject[i];
if(typeof el==="function"){
this.nestedObject[i]=el.bind(this);
}
}
};
To make it easier, may use sth like that ( a helper function):
getfunc:function(...a){
a.reduce((obj,key)=>obj[key],this).bind(this);
}
Use like this:
JsLibTestInstance("nestedObject","nestedobject_function")();
Yea, you are right that the this value in your JSLibTest.prototype.nestedObject function is pointing to nestedObject and not JSLibTest.
If you want to maintain the same call signature, you can declare nestedObject as an IIFE:
nestedObject: (function() {
var that = this;
return {
nested_object_function: function() {
console.log(that);
// this.normal_function();
alert('this.nestedObject.nested_object_function() ran');
}
}
}())
https://jsfiddle.net/dnLzytju/1/
Note: You probably do not want to declare your prototype that way is it effectively deletes all the native prototype methods of the object.
To author your code in a similar way, consider using Object.assign to help you out.
var foo = Object.assign({}, Function.prototype, {
bar() {
console.log("Hello!")
}
});
foo.bar();

Javascript calling other object method

I have these two objects: A and B. I want to call A.something from B, but is not working...
A = function()
{
function something()
{
//do something
}
}
B = function()
{
A.something();
}
this throws "typeError, A.something(); is not a function"...
Your current code attempts to use A as an object when it is a function. You would need to invoke the function A(), but then its something method would still not be available (because it is not exposed).
If you want A to be an object, you could use an object literal like this:
A = {
something: function()
{
//do something
}
}
B = function()
{
A.something();
}
Or for a more classical looking approach you could use new:
function A()
{
this.something()
{
//do something
}
}
B = function()
{
var a = new A();
a.something();
}
There are more ways as well. You can use Object.create or use a more functional approach by returning an object inside the A function.
Don't declare A as a function itself, declare it as an object:
A = {}
Then inside place something as your function:
A = {
something: function() {
//do something
}
}
You will now be able to call A.something().
First of all, to create an object in javascript you have to define your class A like this (easy approach, not using prototyping):
A = function()
{
return {
something = function()
{
//do something
}
}
}
Then create your object by calling var object = A().
So your code should look like this in the end:
A = function()
{
return {
something = function()
{
//do something
}
}
}
B = function()
{
var aObject = A();
aObject.something();
}

Test the context of a method call using sinonjs

I have a class where I bind a method on initialization as follows -
function MyClass() {
this.onHttpCallback = _.bind(onHttpCallback, this);
}
function onHttpCallback(){
//...
}
How do I test if the onHttpCallback when called, is always called with an object of MyClass as context?
I am using sinon.js to mock and the following code doesn't work -
it('should be binded', function () {
//ctrl is an object of MyClass
var dummy_obj = {};
var spy = sinon.spy(ctrl.onHttpCallback);
spy.call(dummy_obj);
spy.alwaysCalledOn(ctrl).should.be.ok;
});
Update
As per the comments in the following answer, it seems like it is impossible to test the binding for a method.
My Take on the problem
//Source.js
function MyClass() {
}
MyClass.prototype.init = function(){
this.onHttpCallback = _.bind(MyClass.onHttpCallback, this);
}
MyClass.onHttpCallback(){
//...
}
//Test.js
it('should bind onHttpCallback', function () {
sinon.spy(_, 'bind');
ctrl.init();
_.bind.calledWith(ctrl.constructor.onHttpCallback, ctrl).should.be.ok;
_.bind.restore();
});
Works like a charm!
In case you wonder why this changes even though you clearly bound it to be MyClass before, that's because you use call with dummy_obj on the spy.
The spy wraps the original function, so it has no concept of that function's binding. It will still accept a different binding on the wrapper function, then try to call the original with that this, which is then ignored by the original function.
var context = {foo: 'bar'};
var original = _.bind(function () { console.log(this); }, context);
var spy = function (original) {
var spyFn = function () {
var _this = this;
spyFn.calledOn = function (ctx) { return ctx === _this; };
return original.apply(this, arguments);
};
return spyFn;
};
var originalSpy = spy(original);
// Will call the spyFn with a different `this`, but will not affect the original binding
originalSpy.call({something: 'else'});
>> {foo: 'bar'}
// Since the spy cannot know the original binding, it will think the assumption is false.
originalSpy.calledOn(context) === false;

Call function within prototype

<script type="text/javascript">
function Test()
{
console.log('constructor');
this.chaninFunction = function(){
console.log('chain me up');
}
}
Test.prototype.callme = function(first_argument) {
console.log('called him');
this.callBack = function()
{
console.log('call back');
}
};
Test.prototype.message = function(first_argument) {
console.log('message him');
};
var test = new Test();
test.chaninFunction();
test.callme();
test.callme().callBack(); //Error undefined
test.message();
</script>
Hi,
I am learning JS at the moment. having experience few situation.
Is there a way i can call the function within the prototype? the above testing i have done result in error. How can i access the function within prototype, or i can't?
It seems that you're saying you want to be able to chain the .callback() after a call to .callme().
Chaining is very simple. The previous method you called simply needs to return an object that contains the next method you want to call. So in your case, both methods are on the same object, so you just need to do return this;.
Test.prototype.callme = function(first_argument) {
console.log('called him');
this.callBack = function()
{
console.log('call back');
}
return this;
};

How can I reference a closure using a string the same way I do it with a member function without using eval?

We have some js code splitted in many files. We have a core file that defines code used by many other js files.
Currently we have something like this:
core.js:
window.mycore = function() {
var myfunction1 = function() {
};
var myfunction2 = function() {
};
var myfunction3 = function() {
//..
var a = myfunction1(b);
//..
};
//...
// many "myfunction"
//...
var myfunctionN = function() {
};
var publish = function() {
for(var i = 0; i < arguments.length; i++) {
try {
window.mycore[arguments[i]] = eval('(' + arguments[i] + ')');
}
catch(e) {
Log.err(600, arguments[i], e);
}
}
};
publish("myfunction1", "myfunction7", "myfunction8",/*...*/"myfunctionM")
}
app.js:
// ...
// ...
var result = window.core.myfunction1("myparam");
// ...
// ...
Note that none core methods are declared as members of the window.core object. Instead they are attached to the core object with the publish function.
This has some pros:
The core code can reference any core function without the need of writing "window.core."
We avoid writing "var myfunction = window.mycore.myfunction = function() ..." in every public function declaration
The exposed methods can be seen centraliced.
But, the use of eval in the publish function is bringing us problems when using code analysis tools since they don't tend to understand eval declarations.
So, here is my question.
Which is the better way to improve this code, so we can keep the advantages mentioned but eradicating the eval declaration.
I am aware of the solution of sending to the publish function some name/value pairs like publish({'myfunction1': myfunction1}, ... ), but I also want to avoid function name repetitions.
Consider that I am not looking for radical changes since there is a lot of code written already.
Thanks!
I'm not sure I understand completely your reasons for using the "publish" method, but is there any reason your not just returning an object with the correct functions from your constructor?
ie:
window.mycore = (function() {
var myFunc1 = function(a) {
alert(a);
};
var myFunc2 = function(b) {
// call to other function in the same scope
myFunc1(b);
}
...
// at the end just expose the public members you want
return {
myFunc1: myFunc1,
myFunc2: myFunc2
};
})();
or
window.mycore = (function() {
return {
myFunc1: function(a) {
alert(a);
},
myFunc2: function(b) {
this.myFunc1(b);
}
};
})();
or, yet another way to end up with the same object :) ... as always there are different ways to get there
(function(){
var o = {};
o.func1 = function(a) {
alert(a);
}
o.func2 = function(b) {
this.func1(b);
}
window.mycore = o;
})();
So, at a fundamental level, I think it would have benefitted you to have written those name spaces as objects. But thats a whole different subject entirely. (and it disqualifies based on the fact that you dont want to do a lot of refactoring).
With that said, my first idea was that you could probably sidestep the need for eval by using the .call() or .apply() method. What they allow you to do is to chain a function call out of your function name. but that doesn't apply to a "string" which is what you're giving your publish function.
so after googling, this is how you execute a function from a string:
var fn = window[settings.functionName];
if(typeof fn === 'function') {
fn(t.parentNode.id);
}
https://stackoverflow.com/a/912642/680578
Personally I prefer the #Jaime approach, but maybe you may do something like
window.mycore = function() {
function myfunction1() {
};
function myfunction2() {
};
function myfunction3() {
//..
var a = myfunction1(b);
//..
};
//...
// many "myfunction"
//...
function myfunctionN() {
};
var publish = function() {
for(var i = 0; i < arguments.length; i++) {
try {
window.mycore[arguments[i].name] = arguments[i];
}
catch(e) {
Log.err(600, arguments[i].name, e);
}
}
};
publish(myfunction1, myfunction7, myfunction8,/*...*/myfunctionM);
}

Categories