Hi all I am new to jquery and javascript.I have written a code and want to test it.But I am stuck at some point and need help from experts.
Here is my jquery class define in myfile.js
$.fn.MyClass = function(arg1 ,arg2, arg3) {
function MyFirstFunc (arg1, arg3) {
//Do some thing
return arg1 + arg3;
};
function MySecFunc (arg2, arg3) {
//Do some thing
};
MyFirstFunc(arf1 ,arg2);
}
And in my index.html file I have to call my jquery class on DOM object like this
$("#div1").MyClass(agr1_val, arg2_val, arg3_val);
Now I want to do unit testing of these functions and keep the test cases in a separate file.I have chose Qunit.
I have wrote following test
test('MyFirstFunction function test', function() {
equal(MyFirstFunc (4, 5),"9" ,"function working correctly");
});
Also in my index_test.html file I have given the path of myfile.js but still Qunit is giving me error
Died on test #1 at file:///var/www/test.js:2:1: MyFirstFunc is not defined
Can any one kindly guide me where I am doing wrong and how to test functions by keeping the test cases in a separate file
Or any other better way to do it.
Thanks
The MyFirstFunc method is not defined. MyFirstFunc and MySecFunc must be defined in the return array in order to publicly use those functions. You can define it like so
$.fn.MyClass = function (arg1, arg2, arg3) {
function MyFirstFunc(arg1, arg3) {
//Do some thing
return arg1 + arg3;
};
function MySecFunc(arg2, arg3) {
//Do some thing
};
return {
MyFirstFunc: function (arg1, arg3) {
return MyFirstFunc(arg1, arg3);
},
MySecFunc: function (arg2, arg3) {
return MySecFunc(arg2, arg3);
}
}
}
And test it with
test('MyFirstFunction function test', function() {
equal($().MyClass().MyFirstFunc(4, 5),"9" ,"function working correctly");
});
The problem isn't with your test case, it's with your function definitions. You can't simply declare a function inside another function and expect to access it in the global namespace. A fundamental property of function definitions in JavaScript is that they're the only things that provide scope, so when you use a function as an object the object's "instance variables" (declared inside the function) are only accessible inside that object.
If you're trying to create an object with methods, you need to assign those functions to instance variables of the object. Instance variables of an object in JavaScript are defined by assigning this.<variable> in the constructor function (the function you use to define the object). So to give MyClass two methods, you should do something like this:
MyClass = function(arg1, arg2, arg3) {
this.myFirstFunc = function(arg1, arg2) {
//Do something
};
this.mySecFunc = function(arg1, arg2) {
//Do something
};
};
var myInstance = new MyClass(x,y,z);
myInstance.myFirstFunc(a,b);
Note that simply giving your functions' arguments the same name as the constructor's arguments doesn't pass the arguments from the constructor to the method. Defining a function does not pass it concrete arguments, so the MyFirstFunc arg1 and arg2 are interpreted as just names of the arguments you might pass to MyFirstFunc, not instructions to pass the outer function's arguments to MyFirstFunc.
Finally, the $.fn property is an alias to jquery.prototype, so what you're doing with $.fn.MyClass = function... is assigning a new property to the JQuery object, essentially patching the library with your own add-on. This probably isn't how you want to define functions in general, though I don't know your use case.
First of all your are declaring bad methods in your jquery object.
Instead of:
function MyFirstFunc (arg1, arg3) {
You should use: this.MyFirstFunc = function(arg1, arg3) {
Also you should call your methods with a jQuery object as in this example:
equal($("#div1").MyClass(1, 2, 3).MyFirstFunc(4, 5),"9" ,"function working correctly");
Here is an example of a working Qunit test:
$.fn.MyClass = function(arg1 ,arg2, arg3) {
this.MyFirstFunc = function(arg1, arg3) {
//Do some thing
return arg1 + arg3;
};
this.MySecFunc = function(arg2, arg3) {
//Do some thing
};
return this.MyFirstFunc(arg1, arg3);
};
$(function() {
$("#div1").MyClass(1, 2, 3);
});
test('MyClass function test', function() {
equal($("#div1").MyClass (1,2,3),"4" ,"function working correctly");
});
Related
This overrides console.log without issue and it makes sense to me:
(function(c) {
console.log = function() {
c.apply(console, arguments);
}
})(console.log);
This one does not work and I don't understand why:
(function(c) {
console.log = function() {
c(arguments);
}
})(console.log);
I just get a list of properties when I call console.log.
What's the difference?
I need to build the array with arguments in the second one for it to work.
It works if you modify your function like this:
(function(c) {
console.log = function() {
// c(...arguments) also works
c(...Object.values(arguments));
}
})(console.log);
console.log('hello world')
This is because arguments is not an array, but an array-like object.
function func(...args) {
console.log(arguments);
}
func(1, 2, "hello", "world")
The second code example doesn't works as you expect it to because you are passing the arguments object as it is to the console.log function whereas in the first code example, due to the usage of apply(), the properties in the arguments object are passed as a separate argument. In other words, array or an array-like object is spread in to distinct arguments.
The console.log call in the first code example is similar to the following:
console.log(arg1, arg2, arg3, ...)
whereas in the second one, it is as:
console.log({ 0: arg1, 1: arg2, 2: arg3, ... });
(function(c) {
console.log = function() {
const a = Array.from(arguments);
c(a.join(" "))
}
})(console.log);
This works.
arguments is an object-like so we need to create the string ourselves.
I have a function like this:
function MyFunction(argument) {
argument()
}
Is there a way to change argument function's arguments?
Example:
MyFunction(function(e) { // e is argument function's argument
// I want to change e using MyFunction function
})
Like...
function MyFunction(argument) {
argument.arguments = "new value"
// but it returns null...
}
You can use bind
Something like:
argument.bind(this, arg1, arg2, arg3, ..., argn)()
Here you can read full documentation:
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind
//function to call
var logger = function(text){console.log(text)}
logger("hello world");
// You want to overwrite the param with a new one
logger.bind(this, "overwritten parameter")("hello world");
I am trying to create a stub definition that the code below could use:
func.calc({
'divide': function(num1, num2) {
// do something
},
'add': function(num1, num2, num3) {
// do something
}
});
So far, I've been having trouble getting the parameters passed to the functions in the second argument. Here's what I've been trying to do:
var func = {
calc: function(operationsArray) {
if (div) {
operationsArray[0](args); /* get args */
}
else (add) {
operationsArray[1](args); /* get args */
}
}
}
Is it possible to get the whole function definition (with parameters and implementation) when it is passed as a parameter like in the first snippet?
You're declaring func.temp as method that accepts an Array as second argument. On the other hand, you call the method with an Object as the second argument.
JavaScript specification tells us that field order is not guaranteed:
4.3.3 Object
An object is a member of the type Object. It is an unordered collection of properties each of which contains a primitive value, object, or function. A function stored in a property of an object is called a method.
meaning you shouldn't access in_func & in_func2 using location index (i.e. [0]).
You should either call the function with an array like this:
func.temp(mainArg, [
function(arg1, arg2) {
// do something
},
function(arg1, arg2, arg3) {
// do something
}
]);
OR, implement the function so that it uses explicit names:
var func = {
temp: function(arg1, func_obj) {
// do something with arg1
if (trigger1) {
func_obj.in_func(/* get params */);
}
else (trigger2) {
func_obj.in_func2(/* get params */);
}
}
}
I've seen many questions for that context, but I still can't figure out, what exactly my Problem is. (I'm still experimenting with JavaScript, especially with objects)
Code:
function Field(val)
{ var value = val;
this.__defineGetter__("value", function(){ return value; });
this.__defineSetter__("value", function(val){ value = val; if(this.onchange) this.onchange.call(); });
}
function LW_makePlan()
{
/* [...] */
this.Filter1=new Field("");
this.Filter2=new Field("");
this.Filter3=new Field("");
this.init = function()
{
/* [...] */
this.Filter1.onchange=this.getSomething;
}
this.getSomething = function()
{
arg="modus=doWhat";
arg=arg+"&filter1=" + this.Filter1.value;
arg=arg+"&filter2=" + this.Filter2.value;
arg=arg+"&filter3=" + this.Filter3.value;
request_fkt(null, true, arg , this.setSomething);
}
this.setSomething = function(data)
{
alert(data);
}
this.init();
};
What I'm trying:
test = new LW_makePlan();
test.Filter1.value="anything";
test.Filter1 has an "onchange"-property, that is checked in the setter of "Field". if set, the setter will also call the object given within the onchange-property.
this works so far BUT it seems, that this call creates a whole new object-instance ... no not an instance, it is, as if the function "getSomething" is copied as a stand-alone function, because the Code i called, but for example this.Filter1 within the function "getSomething" is undefined ...
Why is this happening and how can I avoid this?
PS: I don't want to use some type of event-handling-Things from 3rd Party codes, I'd like to do it myself with a little help maybe.
EDIT:
Thanks to Steffen Heil, changed to:
var scope=this;
this.Filter1.onchange=function() { scope.getSomething(); };
and it works!
Your call to this.onchange is in Field, so you are calling a function of Field. The assignment this.Filter1.onchanged=this.getSomething kind of copies the method getSomething from LW_makePlan to Field, where it will be called.
So inside of getSomething that is now called onchanged the reference this referes to the Field not the LW_makePlan.
Replace the assignment with this:
var source = this;
this.Filter1.onchange = function() { return source.getSomething(); };
And it will work. Most frameworks have a bindmethod that makes this more readable (hiding the extra variable in a scope).
In reply to the first comment:
You can explicitly call a function like this:
x.call( object, arg1, arg2, ag3 );
x.apply( object, [ arg1, arg2, arg3 ] );
These the are the same and it does not matter what x is. Inside the called function this has the value of object.
x can be:
alert
window.alert
(function(){})
(alert)
(window.alert)
Normal calls to a function are shortcuts:
object.f = g;
object.f( arg1 ) => g.call( object, arg1 );
f( arg1 ) => f.call( window, arg1 );
While window is the global object in a browser; other environments may use another global object.
While the difference between these two shortcuts seems tivial, what about the following?
(object.f)( arg1 )
This is completely valid javascript, as object.f is a function and a function can be invoked using (args1). But:
object.f = g;
(object.f)( arg1 ) => g.call( window, arg1 )
So a.f = b.f; copies a member reference from a to b, but the this context, the code is executon on depends on the way f is called.
a.f(x) == a.f.call(a,x) == (a.f).call(a,x) == b.f.call(a,x) == (b.f).call(a,x)
b.f(x) == b.f.call(b,x) == (b.f).call(b,x) == a.f.call(b,x) == (a.f).call(b,x)
By the way, you can define your own bind very easily:
function bind( object, method ) {
return function() {
return object[ method ].apply( object, arguments );
};
}
Then the original code would become:
this.Filter1.onchange = bind( this, 'getSomething' );
This would match the fix I gave above using "late binding". Most libraries prefer "early binding":
function bind( object, method ) {
return function() {
return method.apply( object, arguments );
};
}
Then the original code would become:
this.Filter1.onchange = bind( this, this.getSomething );
The advantage is better performance, but the main difference is what happens, when getSomething changes after bind was called. The first implementation calls the new value, the second the old value.
Does jQuery provides a API to call functions binding the this variable to the jQuery object? E.g.:
function log() {
console.log(this);
}
$('body').execute(log); // prints the $('body') object in the console
I know that this could be solved by making the log a plugin, but I don't want to do that because the function I need to call is generic and I don't want to tie it to jQuery.
EDIT:
jQuery has no execute method, its just a snippet I added to demonstrate what I am trying to achieve.
EDIT 2:
I am not asking how to workaround this problem (underscore.js bind already got me covered), I am only asking if jQuery already provides a similar API.
You can do this "without" having jQuery to implement anything, just "flip" things around a bit and use function-name.apply (object, arguments)
function func (arg1, arg2) {
console.log ("ARG1: " + arg1);
console.log ("ARG2: " + arg2);
console.log ("using this: " + this.html ().length + "\n");
}
func.apply ($('body'), ['abc','123']);
func.apply ($('body')); // 2nd argument is optional
output
ARG1: abc
ARG2: 123
using this: 51645
ARG1: undefined
ARG2: undefined
using this: 51645
this isn't going to be what you want it to be in your scope. You can use an anonymous function with a parameter, though:
function log($this) {
console.log($this);
}
$('body').execute(function() { log($(this)); }); // prints the $('body') object in the console
Check this out:
$.fn.prototype.execute = function() {
var f = function(){ console.log(this)};
$.proxy( f , this )()
// that means something like
// f.call(this)
}
Assume , you have function:
var f= function( arg1, arg2){
console.log(this, arg1, arg2)
}
There you call f passing context and arguments
f.call(document.body, arg1,arg2);
or arguments as array by apply method
f.apply(document.body, [arg1,arg2]);
In both cases you will get
>> <body>...</body>, valOfarg1, varOfarg2