I was trying to write some javascript function and realised that
function testFunction(input_1, input_2, input_3) {
alert("alert");
}
however when i call the function like this:
<input type="button" value="click" onclick="testFunction("1", "2")">
why will it still work even with just two parameters?
You can call a Javascript function with any number of parameters, regardless of the function's definition.
Any named parameters that weren't passed will be undefined.
Extra parameters can be accessed through the arguments array-like object.
It doesn't actually matter how many parameters you are providing. the function interprets them and creates the arguments object (which acts as an array of parameters).
Here's an example:
function sum(){
if(arguments.length === 0)
return 0;
if(arguments.length === 1)
return arguments[0];
return arguments[0] + sum.apply(this, [].slice.call(arguments, 1));
}
It's not the most efficient solution, but it provides a short peak at how functions can handle arguments.
Because javascript treats your parameters as an array; if you never go beyond the second item, it never notices an argument is missing.
Javascript does not support Method overloading hence method will be execute in order of their occurence irrelevant of arguments passed Because javascript has no type checking on arguments or required qty of arguments, you can just have one implementation of testFunction() that can adapt to what arguments were passed to it by checking the type, presence or quantity of arguments..
Because Parameters are optional
Some Reading:
http://www.tipstrs.com/tip/354/Using-optional-parameters-in-Javascript-functions
Javascript is a very dynamic language and will assume a value of "undefined" for any parameters not passed a value.
Try using the below code
var CVH = {
createFunction: function (validationFunction, extParamData, extParamData1) {
var originalFunction = validationFunction;
var extParam = extParamData;
var extParam1 = extParamData1;
return function (src, args) {
// Proxy the call...
return originalFunction(src, args, extParam, extParam1);
}
}
}
function testFunction(input_1, input_2, input_3) {
alert("alert");
}
and you can call this function as below
<input type="button" value="click" onclick="CVH.createFunction(testFunction('1', '2'),'3','4')">
The third parameter can be optional and will have a null undefined default value.
If you explicitly want to have a required parameter, you need to require it via code inside the function.
Related
I want to check that if a member function of a particular name exists on a object, if it does call the member function or make a reference of that member function.
Here I don't have type of the object, i.e. the object maybe does not implement any interface but has a member function cancel().
I used this method (reflection) to check if the member function exists, i.e. if (object::class.members.any { it.name == "cancel" }) and when this statement returns true I am sure that the method does exist but compiler is still unsure that the 'cancel' method exist in the object or not
fun canceller(object: Any): KFunction<Any>?
{
var canceller: KFunction<Any>? = null
// check if object has member function 'cancel'
if (object::class.members.any { it.name == "cancel" })
{
// make reference of that member function and return it
canceller = object::cancel //cancel is still not recognized as a member function and gives an error that "Unresolved reference: cancel"
// or just call it now
// object.cancel()
}
return canceller
}
I expect that canceller variable should be assigned to value.cancel(), but the compiler is unsure that cancel() function exist (with an error "Unresolved reference: cancel") in the object even after we supplied a check inside if statement
It's not meant to be used like this. Reflection is something you use if you don't know at compile time what you are dealing with at runtime. Some examples:
you need to use a type that's configured in some properties file (Class.forName("someTypeString").newInstance())
you have written an utility that extracts the contents of your object for debugging purposes
you need to access code that isn't really visible to you (private fields that you can't easily access, but you need to)
many more... but most of the time very special use-cases
Now what you have shown is a function reference (object::cancel). In order to use a function reference the compiler must know the type of object and the cancel-function must exist for that type. As object is of type Any and the if-condition is only relevant at runtime, the compiler does not know that there is a cancel-function available and therefore compilation fails.
Note that if you aren't doing anything special, you should rather check for a common type/interface. So for example, if your objects implement an interface Cancellable you could just change your code to something as follows:
fun canceller(object: Any): KFunction<Any>? {
var canceller: KFunction<Any>? = null
// check if object is of type Cancellable
if (object is Cancellable) {
// make reference of the Cancellable::cancel-function
canceller = object::cancel // smart-cast acting
// or you could also call it directly: object.cancel()
}
return canceller
}
or probably you could just spare that function altogether and end up with something like just:
val someObj : Cancellable = ...
// somewhere later:
someObj.cancel()
Reflection is rather expensive and if you aren't entirely sure what it is useful for, you should not use it.
If you really knew what you were doing... then ok... it's of course also possible to call that function via reflection and if you ask for the existance of a function via reflection you also have to call it via reflection:
object::class.members.first {
// note: I am using just the first function... if there are several, you need to check which one to use (parameter/type)
it.name == "cancel"
}
.call(object)
I think you can use reflections for this purpose.
myObject.javaClass.kotlin.members.any { it.name == "cancel" }
And the better way to express the idea of "object that has all the variables" is to define the interface and have all those object implemented
interface Achiever { val name: String }
In this example:
public function Roulette() {
new QuickLoad(url, function (o:*):void {trace(this);});
}
when QuickLoad instance does its stuff, it calls the anonymous function. One would think that this is Roulette. But no, it turns out to be the anonymous function's caller, which is QuickLoad.
This is weird to say the least, say how am I supposed to pass the "correct" this (i.e. Roulette instance) inside the anonymous function if I don't do it the normal way?
Just save the outer this instance under a different name so that it is preserved:
public function Roulette() {
var rouletteThis = this;
new QuickLoad(url, function (o:*):void {trace(rouletteThis);});
}
There is a way to call a function with an alternate this pointer, but since your function is called from within new QuickLoad(), you need to alter that call statement, and pass your this as Roulette into the constructor. Your new QuickLoad object is unaware of its surroundings, and even the caller of the constructor is unknown to it. Thus, you need to make it aware, pass a this pointer from Roulette() to QuickLoad(), AND call the function from QuickLoad with passing an alternate this pointer.
public function QuickLoad(url:String,caller:Object=null,callback:Function=null) {
// initialization code
if (callback!=null) {
if (caller!=null) callback.apply(caller,[o]);
else callback.apply(this,[o]);
}
}
...
public function Roulette() {
new QuickLoad(url, this, function (o:*):void {trace(this);});
}
Function::apply() manual.
You can also use call() method, if your argument array has fixed length. callback.call(caller,o);
Generally, in this context, this refers to an object. To quote a rather infamous acronym: INABIAF (It's not a bug, it's a feature), LOL. So, yes, the object instance QuickLoad that is calling the function is going to be what this looks at by default.
There is an exception I know of (out of many, I'm sure)...you can get anything...variable, function, object, whatever, via this["Name of Object"]. But that's an aside.
There ARE other workarounds, I'm sure, which may or may not be practical for your purposes. This is one way of passing a function, out of many, and it's the one I use the most.
Functions do not have instances. They're not objects. If you want to send a function as an argument to another function, you simply pass it, as follows in this rather weird example.
//This function accepts a function as an argument.
function bridgeOfQuestions(person:String, response:Function):void
{
if(person == "King Arthur")
{
response("What is the average airspeed velocity of an unladen swallow?");
}
else
{
response("What is your favorite color?");
}
}
//This is the function we're going to pass.
function askQuestion(question:String):void
{
trace(question);
}
//Here, we call bridgeOfQuestions and pass it the askQuestion function.
//NOTE: Leave off the parenthesis on the function being passed!
bridgeOfQuestions("Sir Lancelot", askQuestion);
bridgeOfQuestions("King Arthur", askQuestion);
EDIT: If it is just the name you're passing, a function is a function permanently. It doesn't change, unlike an object, and as I said, it doesn't have instances. Therefore, if you merely want to print out the name of the function, you'd only use trace("Roulette").
I'd like to reference a get function as a Function object rather than as the value that it returns.
Normally i would be able to simply refer to the function without parenthesizes like so:
private function getFoo():int {
return 0;
}
trace(getFoo); // traces function
But the whole point of get functions is that you can call the function without the parenthesizes, so i just get a return of 0 if i do this:
private function get foo():int {
return 0;
}
trace(foo); // traces 0
Is there be any way at all to grab a reference to the foo function object?
Your first example gets a reference to the function (as it traces Function).
There is no way to get a reference to a getter, as getters are not simple functions, but a representation of a (custom) property of that object. They are not meant to work as a standard ones and so they are not meant to be referenced.
I cannot imagine why would you want to get a reference to that getter? And also, getters are not meant to be used only because you can skip those two symbols ()..
To make public API of SWF more reliable, I usually wrap callbacks in closure with try/catch block:
private function addCallback(functionName:String, closure:Function):void {
ExternalInterface.addCallback(functionName, wrapEventHandler(closure));
}
private function wrapEventHandler(closure:Function):Function {
var self:Main = this;
return function(...arguments):* {
try {
return closure.apply(self, arguments);
} catch (error:Error) {
// Print error report here
}
}
}
When exception occurs in 'closure', error report will be printed.
I noticed that it works fine even when using 'null' instead of 'self':
closure.apply(null, arguments);
Is it safe to use 'null' in this case?
Callback I register with ExternalInterface aren't static functions; they use Main's class fields.
It works just fine with null, NaN and self. I couldn't find any problems with using NaN/null.
Passing the this argument to apply() is optional, and the parameter default value is NaN.
Parameters
thisArg:* (default = NaN) — The object to which the function is
applied.
Likewise with, call():
You can pass the value null for the thisObject parameter to invoke a
function as a regular function and not as a method of an object.
For example, the following function invocations are equivalent:
Math.sin(Math.PI / 4)
Math.sin.call(null, Math.PI / 4)
If I set up a function that accepts a callback:
function loadSomething(path:String, callback:Function):void;
And that callback should accept a given type, for example a String to represent some loaded information:
function onLoaded(response:String):void;
// Load some data into onLoaded.
loadSomething("test.php", onLoaded);
Is it possible to assess the function that will be used for callback and ensure that it has both a given amount of arguments and that the argument accepts the correct type? e.g.
function broken(arg:Sprite):void;
// This should throw an error.
loadSomething("test.php", broken);
I don't think you should bother doing this kind of check as it would create an uncessary overhead. You can simply throw the exception when you do the callback:
try {
doCallback(response);
} catch(e:*) {
trace('Incompatible callback');
}
If you really want to do the check, you might be able to do it using reflection. Just call describeType(callback) from flash.utils and parse the XML.
One simple thing you can do is to check the number of acceptable arguments by calling length property on method closure like:
function some ( val1 : int, val2 : int ) : void { return; }
trace(some.length); // traces 2
Other much more complex method maybe is to use AS3Commons bytecode library. You can experiment with dynamic proxies.