I am trying to test if a local method (method1) is being called from another method(method2). I tried something like this but it does not work as the method1() still has the original definition. The code snippet looks like this:
var ClassA = function () {
var method1 = function () {
console.log('method1');
};
var method2 = function () {
method1();
};
return {method1: method1, method2: method2}
}
Test case:
it("should call method1 when method2 is called", function () {
var objectA = new ClassA();
spyOn(objectA, 'method1').andCallThrough;
objectA.method2();
expect(objectA, 'method1').toHaveBeenCalled();
});
Tried overriding method1 to without any success:
objectA.method1 = jasmine.createSpy('aSpy').andCallThrough();
When you call new ClassA() you invoke the ClassA function and get a new object with the related prototype. This means that when you spyOn(ClassA, "doSomething") you're not setting up a spy on the object returned by the new call, but on a possible doSomething function on the ClassA function itself.
You should be able to do something like:
it("calls method1", function() {
var originalConstructor = ClassA,
spiedObj;
spyOn(window, 'ClassA').and.callFake(function() {
spiedObj = new originalConstructor();
spyOn(spiedObj, 'method1');
return spiedObj;
});
method2();
expect(spiedObj.method1).toHaveBeenCalled();
});
Please let me know if this works if not we can discuss more.
Related
I have the following code.
function Test() {
this.funct_1 = function() {
alert('funct_1');
}
this.funct_2 = function() {
alert('funct_2');
}
return this;}
function getTestObj() {
var testObj;
if (!testObj) {
testObj = new Test();
}
return function() {
return testObj;
}}
What I'm trying to accomplish is the following. I want to have a class Test which is not singleton. Then in some other places in my application I need to have a function which could return the same instance per script execution. I figured that I could use closure for that getTestObj.
However, when I try to use it
getTestObj().funct_1();
I'm getting the following error, saying the funct_1() is not found.
Cannot find function funct_1 in object function () {...}.
Clearly, I'm making some kind of mistake here, but I'm not able to find any solution over the net which could help me. Would appreciate any comments.
NOTE: I'm forced to use ECMA5
testObj is wrapped inside a function
So, either call it
getTestObj()().funct_1(); //notice two ()()
Save the value of getTestObj() in a variable
var singleTon = getTestObj();
var testObj = singleTon();
testObj.funct_1();
Or, simply return testObj (in case singleTon isn't required)
function getTestObj()
{
var testObj;
if (!testObj) {
testObj = new Test();
}
return testObj;
}
And invoke it as
getTestObj().funct_1(); //notice single ()
getTestObj() is returning a function i.e. :
function() {
return testObj;
}
So you have to call it again getTestObj()(), this will return the Test's object and now you can access it's properties.
getTestObj()().funct_1();
OR
You can change your getTestObj function as :
function getTestObj() {
var testObj;
if (!testObj) {
testObj = new Test();
}
return (function() {
return testObj;
}());
}
I have a context function type that is defined as below:
var Context = function () {
this.run = function () {
method1();
method2();
}
var method1 = function () {
}
}
As it is clear in the definition, method2 is not defined in the context. I need every instance of Context passes its implementation of this method.
var c = new Context();
// This does not work! because the call in run() function
// is not this.method2();
c.method2 = function () {
alert("injected method2");
};
c.run();
I need to keep method2() in run without use of this object i.e. this.method2();
Any solution?
If you can define method2 before creating Context it will work no problem:
function method2() {
alert(2);
}
var c = new Context();
c.run();
You can add method2 to the window object instead of the c object, in which case it will work.
Note that this is a clear indicator of poor design. You should probably look into doing this differently.
Callback approach:
var Context = function (callback) {
this.run = function () {
method1();
if(callback) callback();
}
var method1 = function () {
}
}
var c = new Context(function () {
alert("injected method2");
});
c.run();
If you change your run method to the following it should work as expected
this.run = function () {
method1();
this.method2();
}
UPDATE: I just realized it looks like you want to be able to do this on all instances of Context objects. In that case you would also need to define method2 on Context.prototype and not just on c
Context.prototype.method2 = function () {
console.log("injected method2dfd");
};
Let's say I have a class that is designed to have some callbacks added to it later on.
function myclass() {
this.onSomething = function () {};
this.onOtherThing = function () {};
this.something = function () {
// stuff
this.onSomething();
};
this.otherThing = function () {
// other stuff
this.onOtherThing();
};
}
I can't have this.onSomething and this.onOtherThing being undefined or null because when they are called in something() and otherThing(), an error will be thrown, stating that their type is not a function.
Since those empty functions are needed, but they use memory, is the class going to be more memory efficient if I did this?
function myclass() {
this.onSomething = empty;
this.onOtherThing = empty;
...
}
function empty() {
}
This way each class instance's properties point to the same empty function, instead of creating new functions every time. I assume defining an empty method doesn't take a lot of memory, but still... is this technically better?
You are right about the fact that a new function is created for every instance of your class. In order to have this shared across all instances you can declare it on the prototype of the class:
var MyClass = function() {
this.something = function () {
// stuff
this.onSomething();
};
this.otherThing = function () {
// other stuff
this.onOtherThing();
};
}
MyClass.prototype.onSomething = function() {};
MyClass.prototype.onOtherThing = function() {};
This way, the methods will be shared by all instances.
why don't you try to return true or return false instead of returning empty functions.
or best you can use :
function myclass() {
this.onSomething = false;
this.onOtherThing = false;
...
}
as per your comment you can try :
function myclass() {
this.onSomething = empty();
this.onOtherThing = empty();
... }
function empty() {
//return something
return true;
}
Prototype js allows to call super method by $super. I need call class-method from object, but in overriden method, like this:
var ClassA = Class.Create({
initialize: function(options) {
Object.extend(this, options);
},
method1: function(){/*some code*/}
});
var ClassB = Class.Create(ClassA, {
method1: function($super) {
$super(); // this works fine, calls ClassA.method1()
}
});
var objectA = new ClassA({
method1: function($super) { // I need something like this
$super(); // this not works, must calls ClassA.method1()
}
});
How can I do this?
If you want just objectA to have the new method, do this:
var objectA = new ClassA();
objectA.method1 = objectA.method1.wrap(function (fn) {
fn(); // works like a `$super` call inside of a class
});
It uses Function#wrap to add advice around the function.
If you need to pass arguments to the function, do this:
var objectA = new ClassA();
objectA.method1 = objectA.method1.wrap(function () {
var args = $A(arguments), fn = args.shift();
fn(args); // works like a `$super` call inside of a class
});
If you want to redefine the method in an already defined Class you need to use Class#addMethods
var ClassA = Class.Create({
initialize: function(options) {
Object.extend(this, options);
},
method1: function(){/*some code*/}
});
ClassA.addMethods({
method1: function() {
/** does something else **/
}
});
However this will overwrite the method1 method and not create a subclass or child method of the original one
http://api.prototypejs.org/language/Class/prototype/addMethods/
For my needs I find next decision:
function singleton() {
var AnonymousClass = Class.create.apply(Class, arguments);
return new AnonymousClass();
}
This function get me chance to override any method in class.
Example
singleton(ClassA, {
method1: function($super) {
/* call of $super() */
}
})
This work for me as I wanted. Function returns for me object with overrided method from class, but this method can calls $super.
I have tried to create javascript object like
function Caller() {
this.init = function() {
makeCall();
};
this.makeCall = function(){/*come code here*/}
}
var a = new Caller();
a.init();
I got error function is not defined, same thing happens when I try to call this.makeCall();
When I remove this from makeCall definition it works, but when I remove also from init it doesn't work. How to solve this ?
Use this.makeCall(). Additionally define makeCall() before its use.
function Caller() {
this.makeCall = function () { /*come code here*/ }
this.init = function () {
this.makeCall();
};
}
var a = new Caller();
a.init();
DEMO
Use this.makeCall() it is a method so you can use it.
Try this this.makeCall() function is executed successfully here.
<html>
<head>
</head>
<body>
<script>
function Caller() {
this.init = function() {
this.makeCall();
};
this.makeCall = function(){
alert('hello');
}
}
var a = new Caller();
a.init();
</script>
</body>
</html>
You need to call the function properly using this
makeCall(); => this.makeCall();
You can use IIFE to declare Caller:
var Caller=(function () {
function constructor() {
}
function makeCall() {
/*come code here*/
}
constructor.prototype.init=function () {
makeCall.apply(this, arguments);
};
return constructor;
})();
var a=new Caller();
a.init();
and be sure that Caller is loaded before it is invoked.
To answer your question and to enhance your code you should have a look at this:
function Caller(){};
This is your constructor.
You can then add methods to your constructor like this:
Caller.prototype.init = function () {
// do something
}
When you create instances of your "class" Caller
var a = new Caller();
every instance will have the methods you described in the Caller.prototype object.
And to solve your problem:
If one prototype method wants to call another prototype method, you need to do this:
// do some setup in your constructor
function Caller(phoneNumber) {
this.phoneNumber = phoneNumber;
};
Caller.prototype.init = function () {
// the code word "this" will be the instance itself
this.makeCall();
};
Caller.prototype.makeCall = function () {
// do whatever this method needs to do
alert('calling ' + this.phoneNumber);
};
var a = new Caller(0123456789);
a.init();
The main thing to understand is, that in every prototype method, the keyword this references the current instance of the constructor (in this case Caller).