I've done some leg work on getting this code to behave the way I want it to up to a certain point.
However I have encountered problem that requires a little bit of direction in helping me to solve the issue.
Problem to solve
Comments in code will explain what I am trying to archive..
var myArr = ["Brent white","brentw.white"];
function nameFoo (name){
var strSplit = name.split(" "); // splitting Brent White
var nameStr = this. myArr; // fetching Brent white string from myArr
console.log (strSplit,myArr[0]);
}
nameFoo("Brent White"); // calling nameFoo function
var myData = {
someData:"somedata",
someMoreData:"moredata",
myName:function(){
// I need to call nameFoo function through myName method.
// My hypothesis is that return will use the (this) keyword within the object?
}
};
// Here I need to call the method to have access my nameFoo? Correct me if I am wrong?
// Is this method invocation?
// Please help..Lost here...
To sum it up, I want myName method to call the nameFoo function. nameFoo will then give me myName method the result.
If someone could be kind enough to demonstrate how to get through this last step then I would be very grateful.
Pointing me in the right direction would also be greatly appreciated..
PS I am new to JS.
Be careful with the 'this' keyword. By calling nameFoo in a global context ie:
// some code
nameFoo(arg);
// some more code
'this' will always refer to 'window'. So, when you call myData.myName, even though this object calls the nameFoo method, 'window' will still be referenced in nameFoo's 'this'. 'this' is normally scoped to the object the function belongs to.
If you need 'this' to refer to one of your custom objects, use the Function prototype method "call" from within your myName function.
var myData = {
...
...
myName: function() {
nameFoo.call(this, someArgument);
};
Note that someArgument will be the argument passed to 'nameFoo' -- which will throw an error if you do not supply an argument. It's up to you to figure out what you want to pass.
More info about Function.prototype.call:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
More info about Function.prototype.apply:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
The only real difference between the two is how you supply arguments to the function you are calling. With "call", you separate the arguments with commas (as you would when normally executing a function).
eg: nameFoo.apply(this, arg1, arg2, arg3);
With "apply", you supply the arguments as an array.
eg: nameFoo.apply(this, [arg1, arg2, arg3]);
I'm thinking this conceptually may help you out:
// Some names in array
var my_names = ["Brent White", "John Smith"];
// Returns name array [First, Last]
function nameParse(full_name) {
return full_name.split(" ");
}
// Person object (properties)
function Person(name) {
this.full_name = name;
this.name_array = nameParse(name);
this.first_name = this.name_array[0];
this.last_name = this.name_array[1];
}
// Create single person example
var brent = new Person(my_names[0]);
// Access properties of brent
console.log(brent);
console.log("Hey, my first name is " + brent.first_name);
// Alternate example --------- //
// Store our people here
var my_people = [];
// Create a person for each name
for (var i = 0, max = my_names.length; i < max; i += 1) {
var some_person = new Person(my_names[i]);
my_people.push(some_person);
}
console.log(my_people);
Related
How does the new work differently in the 2 examples below? I see that the 2nd example is replacing the annoymous funciton with a variable, but in the second one, the function/class "Person" is actually being called. Does it make any difference if it's being called or not? I tried it without the calling and it still worked. So that led me to believe that new is actually calling the function and setting up this to be assigned to the instance variable.
var person = new function() {
this.setName = function(name) {
this.name = name;
}
this.sayHi = function() {
return "Hi, my name is " + this.name;
}
}
person.setName("Rafael");
console.log(person.sayHi()); // Hi, my name is Rafael
var Person = function() {
this.setName = function(name) {
this.name = name;
}
this.sayHi = function() {
return "Hi, my name is " + this.name;
}
}
var personTwo = new Person()
personTwo.setName("Rafael");
console.log(personTwo.sayHi()); // Hi, my name is Rafael
There would be almost no difference between these two examples, if it was a simple function like this:
(function() { console.log("IIFE"); })();
// or
var f = function() { console.log("Function"); };
f();
You just store your function in a variable, and then call it.
However, it makes a little difference, since it is related to JS OOP mechanisms. In the first case you get Object instance, and in the second you get Person instance. This makes difference in OOP sense.
var person = new function() { };
console.log("Is instance of: " + person.constructor.name);
console.log("There is no way to check instanceof in this case");
var Person = function() { };
var person = new Person();
console.log("Is instance of: " + person.constructor.name);
console.log(person instanceof Person);
In general, new and classes are supposed to be used as in the second case in order to enable the full functionality of JS OOP. There is absolutely no sense or/and advantage in using anonymous class constructor.
Whether or not it is assigned into a variable: does not matter. It is completely parallel to this example:
var x = 1;
console.log(x);
and
console.log(1);
Whether it needs to be called or not: A function with the new operator is always being called, but with new, parentheses are optional when no parameters are passed: new Person() is equivalent to new Person, but new Person("Joe") cannot be done differently.
In the second example, you are passing to the new operator the exact same function. You simply are using a reference (logically stored in a variable) instead of writing literal function just in place.
So, your second example is the same as:
var personTwo = new (function() {
[...]
})()
[...]
Which, in fact, is much the same as the first one:
var person = new (function() {
[...]
})
[...]
NOTE that the parentheses surrounding the function are absolutely optional in this case. You could be placed there seven if you like: (((((((function(){[...]}))))))).
The point here is that when you say «in the second one, the function/class "Person" is actually being called» you are WRONG there: That function, which acts as a constructor isn't being called by you. You are simply passing it as a parameter (the constructor function) of the new operator which is, in fact, who is actually calling the constructor with the rest of parameters you provided, if any.
See new syntax documentation:
new constructor[([arguments])]
The constructor is the function you pass to the new operator and the parameters are specified between parentheses. But they are fully optional (including the parentheses itself).
This is why new constructor; without parentheses works.
To be clear: What you thought happens (but not) would be written as:
var person = new ((function(){...})()) ();
...or, more verbosely:
var person = new (
(function(){ // Constructor builder.
[...]
return function(){...}; // Actual constructor.
})() // Constructor builder call
//v-- Parentheses to force builder to be called.
) (); // <-- Parameters (if any) passed to the constructor.
Everything started with this Question
Then an answer from #MinusFour
var slice = Function.call.bind(Array.prototype.slice);
I wanted to understand, whats happening under the hood,
my curiosity hence this Question.
what to achieve ? understanding of "Function.call.bind".
Step-by-step approach for the same
Started with MDN
NOTE : I am using NodeJS here
1)
var adder = new Function('a', 'b', 'return a + b');
console.log(adder(2, 6));
**OUTPUT **
8
This is expected, Nothing Fancy
2)
This is our end goal , calling function myFunc from the bounded
function (Function.call.bind(myFunc))
function myFunc(a, b) {
console.log(arguments.length, a, b, a + b);
}
3)
var adder = Function(myFunc);
console.log(adder.toString())
OUTPUT
function anonymous() { function myFunc(a, b) { console.log(a + b); } }
Expected! above code does nothing, because i am calling 'anonymous' ,
and it does nothing.
4)
var adder = Function.call(myFunc);
console.log(adder.toString())
OUTPUT
function anonymous() {
}
Expected!. '.call' calls 'Function', with 'this' set to 'myFunc' and with out any param or function body. so an empty anonymous function is the output. Now, I can do "var adder = Function.call(myFunc,myFunc);" to create the same function from step-3
So far so good
5)
var adder = Function.call.bind(myFunc);
console.log(adder.toString())
adder(2,6);
OUTPUT
function () { [native code] }
1 6 undefined NaN
Here first param is not passed to the 'myFunc' function.
this is taken as 'this' for function 'adder' (the bounded Function.call) ?
Now I understand(or did I misunderstood?) until now, but then
How does below code works ?
var slice = Function.call.bind(Array.prototype.slice);
function fn(){
var arr = slice(arguments);
}
in my case first param to adder is discarded(or Function.call consider it as 'this' for it), same should happen with slice above right ?
Anyway, i wanted to document it for a reference
I'm afraid you've gone off in slightly the wrong direction. This line:
var slice = Function.call.bind(Array.prototype.slice);
never calls Function and never arranges for it to be called later. The only thing Function is being used for there is its call property. Function could have been Object or Date or RegExp or any other function, or could have been Function.prototype; doesn't matter. Function.prototype would have been more direct and possibly less confusing.
This is a bit tricky to explain because it involves two layers of dealing with this, where this is different things at different times:
The call function calls functions with a specific this value you give it as its first argument, passing along any other arguments you give it. For example:
function foo(arg) {
console.log("this.name = " + this.name + ", arg = " + arg);
}
var obj = {name: "bar"};
foo.call(obj, "glarb"); // "this.name = bar, arg = glarb"
There, because we called call on foo, call called foo with this set to obj and passing along the "glarb" argment.
call knows what function it should call based on what this is during the call call. foo.call sets this during call to foo. That can be confusing, so let's diagram it:
foo.call(obj, "glarb") calls call:
call sees this = foo and the arguments obj and "glarb"
call calls this (which is foo):
foo sees this = obj and the single argument "glarb"
With regard to slice, you normally see call used with it used to create an array from something array-like that isn't really an array:
var divArray = Array.prototype.slice.call(document.querySelectorAll("div"));
or
var divArray = [].slice.call(document.querySelectorAll("div"));
There, we call call with this set to Array.prototype.slice (or [].slice, which is the same function) and passing in the collection returned by querySelectorAll as the first argument. call calls the function it sees as this, using its first argument as this for that call, and passing along any others.
So that's the first layer of this stuff.
bind is another function that functions have, and it's similar to call but different: Where call calls the target function with a given this and arguments, bind creates and returns a new function that will do that if you call it. Going back to our foo example:
function foo(arg) {
console.log("this.name = " + this.name + ", arg = " + arg);
}
var obj = {name: "bar"};
var fooWithObjAndGlarb = foo.bind(obj, "glarb");
fooWithObjAndGlarb(); // "this.name = bar, arg = glarb"
This is called binding things (obj and the "glarb" argument) to foo.
Unlike call, since bind creates a new function, we can add arguments later:
function foo(arg) {
console.log("this.name = " + this.name + ", arg = " + arg);
}
var obj = {name: "bar"};
var fooWithObj = foo.bind(obj);
fooWithObj("glarb"); // "this.name = bar, arg = glarb"
Okay, now we have all our working pieces. So what's happening in your code? Let's break it into parts:
// Get a reference to the `call` function from the `call` property
// on `Function`. The reason `Function` has a `call` property is that
// `Function` is, itself, a function, which means its prototype is
// `Function.prototype`, which has `call` on it.
var call = Function.call;
// Get a reference to the `slice` function from `Array.prototype`'s `slice` property:
var rawSlice = Array.prototype.slice;
// Create a *bound* copy of `call` that, when called, will call
// `call` with `this` set to `rawSlice`
var callBoundToSlice = call.bind(rawSlice);
(callBoundToSlice is just called slice in your question, but I'm using callBoundToSlice to avoid confusion.) Binding rawSlice to call was the first layer of this handling, determining what call will see as this. Calling callBoundToSlice will call call with this set to rawSlice. Then call will call the function it sees as this (rawSlice), using its first argument as the value for this during the call (the second layer of this handling) and passing on any further arguments.
So our forEach with a collection from querySelectorAll can now look like this:
callBoundToSlice(document.querySelectorAll("div")).forEach(function(div) {
// Each div here
});
That passes the collecton returned by querySelectorAll into callBoundToSlice, which calls call with this as rawSlice, which calls Array.prototype.slice with this set to the collection. Array.prototype.slice uses this to copy the array.
All of that said, using slice to turn array-like objects into true arrays is a bit out of date. ES2015 introduces the Array.from method, which can be shimmed/polyfilled on JavaScript engines that don't have it yet:
var divArray = Array.from(document.querySelectorAll("div"));
I have this global variable which contain function names. I am able to execute the function without parameters, but after passing some parameters, I get this error below.
"Uncaught TypeError: undefined is not a function"
//Globally Called and refilled with function names
var function_name = new Array();
//This is the function that executes the var that contains function name
function execute(){
var function_count = function_name.length;
while (function_count--)
{
window[function_name[function_count]](arguments);
}
}
//This is how I add the function with its parameters
function_name.push("GetStatusDetails("+ sampleData +")");
Could you guys guide me with this I am newby in javascripting. Using the function above. Thanks everyone.
You cannot use arguments like this. This results in the arguments pseudo-array being passed as the first parameter. You need to do
window[function_name[function_count]].apply(window, arguments);
However, as mentioned in a comment, you also need to store a pure function name in your function_name array, and pass the arguments to execute, as in
function_name.push("GetStatusDetails");
execute(sampleData);
But why are you passing function names around? Just pass the functions around. So:
function_name.push(GetStatusDetails);
Then you call it directly, instead of pulling it out of the window object by name:
function_name[function_count].apply(window, arguments);
If you want to queue up function+params for later execution, then try something like:
//Array of functions to be called
var function_array = new Array();
//This is the function that executes the functions in the array
function execute(){
var function_count = function_array.length;
while (function_count--)
{
function_array[function_count]();
}
}
//This is how I add the function with its parameters
function_array.push(function() {
GetStatusDetails(sampleData);
});
It would be better programming practice to encapsulate some of this along the following lines:
var FunctionQueue = {
_queue: [],
queue : function(fn) { this._queue.push(fn); },
execute: function() { var fn; while (fn = this._queue.pop()) { fn(); } }
};
FunctionQueue.queue(function() { GetStatusDetails(sampleData); });
FunctionQueue.execute();
function_name.push("GetStatusDetails("+ sampleData +")"});
Here you're not pushing back a function but the result of the function call GetStatusDetails(sampleData). window doesn't contain a key of the signature, so trying to find it with window[...] returns undefined. When you try to call it with window[...](arguments) that's how you got the error, because you can't "call" undefined.
sampleData should be passed into execute() at the call sight and you should be pushing back the name of the function:
function_name.push("GetStatusDetails");
Moreover, arguments is an array of the arguments, not the actual arguments. So GetStatusDetails() will have to go through the array to find the actual argument. Go see #torazaburo's answer that gives the correct solution.
Since I can determine the number of arguments a function expects to have by calling its Function.length property, is there any way for me to programmatically create the right number of parameters to insert into that function at runtime? Example:
var xyz = function(a,b) {};
var bcd = function(a,b,c,d,e,f) { }; // vararg example
var doc = document, func_length = xyz.length;
doc.xyz = (function() {
return function(a,b,c,d,e) { /* works for one but not the other */ } }).call(doc);
/* would prefer to `return function(a,b)` with only 2 parameters, if it is
used for function `xyz` (though returning 5 works fine in this case), and to
`return function(a,b,c,d,e,f)` with 6 if used for function `bcd` (which does
not work with only five params). */
// thinking about xyz.apply(null,arguments)...but which arguments..? :(
// Returning function(a,b,c,d,e) does not support functions with more than five
// parameters...which would mostly be varargs - hence my question
// I am also well aware that I can use an object or an array instead of
// using many params.
/* This is for incorporating a user-defined function for use in my code, while
* allowing for my function to do 'other stuff' afterward. (And allowing for
* varargs, of course).
* Because coding something like: doc.xyz = xyz is inflexible */
As you can see, I don't know how to do this, or if it is even possible. The search bar hasn't given me any other questions like this one, otherwise I would not have asked...
NOTE: This answer is a product of misunderstanding but
may help the future visitors of this site.
Another way:
Do you really need to add parameters? Writing the function this way would be enough:
function foo(){ //No arguments predefined
a = arguments[0] || ""; //first argument or (if not defined) empty string
b = arguments[1] || ""; //second argument etc.
c = arguments[2] || ""; //third argument etc.
alert(a+b+c);
}
foo("Hello ", "world!");
This alerts "Hello world".
The solution you want:
The simplest way:
This is what you've asked for but it's not as simple as the previous solution.
You can define a meta function with all the parameters and a handler function that changes over the time.
(function(){ //Wrapper
var foo_meta = function(a,b,c,d){ //Local meta of foo
alert(a+b+c+d); //Do the code
};
window.foo = function(a,b){ //Global foo
return foo_meta(a,b,"","");
};
window.redefine_foo = function(){ //Global foo-changer
//Rewrites foo
window.foo = function(a,b,c){
return foo_meta(a,b,c,"");
};
};
})(); //Wrapper
//Do some code
foo("a","b");
redefine_foo(); //Rewrite foo
foo("a","b","c");
//Note that foo_meta is not defined here
foo_meta == undefined; //It's safe in the wrapper :)
This will alert "ab" and then "abc". For the meaning of wrapper function, see the references.
Reference:
Arguments array: http://goo.gl/FaLM1H
Wrapping code: http://goo.gl/uQ5sd0
If you send two parameters 6 and 7 to a function doWork(a,b,c,d,e),a=7 and b=6 will be automatically set and rest of the parameters will be ignored.
Why not just pass one object into the function and use JQuery extend.
e.g.
var parm =
{ x: 1, y : 2};
f(p) {
p = $_.extend({...defaults here}, p);
...
}
This is an example for joining the arguments, regardless of the number of arguments, to show how function arguments can be turned into an array and then processed like any other array.
function foo(){ //No arguments predefined
// convert to real array
var args = Array.prototype.slice.call(arguments);
// or if Array generics are available
var args = Array.slice(arguments);
console.log(args.join(' '));
}
foo('Hello', 'world!');
foo('Hello', 'wonderful', 'world!');
Here is the fiddle
Ref: arguments MDN
Well, I think I've figured it out at last. I've realized that there may be no way to 'truly' add a parameter to a function the way that I was asking, but there is a way to emulate the same result:
var doc = document;
var xyz = function(a,b) {};
var bcd = function(a,b,c,d,e,f) {};
var obj = {};
// Now, here it is (mostly (sort of)):
obj.userFunc = function(args) {
var args_Array = [];
for (var i=0;i < arguments.length; i++ ) {
args_Array.push(arguments[i])
}
xyz.apply(null,args_Array); // or 'this'. or 'undefined'. Whatever you want.
// do other stuff
return this; // we know what to do to make 'this' scope explicit
} // end
var thisFunc = 'xyz'
doc[thisFunc] = obj.userFunc;
doc.xyz('h','i');
doc.xyz('h','i','j');
doc.xyz('h','i','j','k');
doc.xyz('h','i').xyz('j','l').xyz('j','q'); // etc.
The trick was to use the arguments object, which conveniently assimilated all the parameters into a readily available object, push each value into an array then apply the function.
In case you're wondering what the fuss was all about, I wanted to completely incorporate a user-defined function into another function, while still being able to do 'other stuff' afterward. My previous example worked to an extent, but did not have support for varargs. This does.
This approach is greatly more flexible than: doc[thisFunc] = userDefinedFunction
:) 4/26/2014
I found something strange..
function Man(){
this.Man = "Peter";
}
after I call it. (not use it as a constructor)
Man()
I think a result will be
alert(Man.Man)//-->Peter
but.. I'm wrong , actually the result is :
alert(Man.Man)//-->undefined
alert(Man)//-->Peter
That was really confusing ,how it happened??
I'll explain you what is happening there.
1
function Man(){
this.Man = "Peter";
}
The this in Man() function is window.
2
Man();
You are calling the function. Which sets the global variable Man's value to "Peter".
Note that this.Man = "Peter" is equal to window.Man = "Peter" as this is referring to the window.
3
alert(Man.Man)
The function call Man(); in step 2 has made the Man from a function to a string variable. Now Man is a variable whose value is a string and it doesn't contain the property Man, so it is undefined.
4
alert(Man)
Now, you are actually alerting the global variable which was created in Man() call and it was set the value of "Peter"
I used the chrome console and had some other findings
function Man(){
this.Man = "Peter";
console.log("this", this);
}
Above this refers to Window. If you call the function Man() nothing is returned since the function does not return anything but sets the property Man on the window-object to be Peter. Your line Man.Man should return undefined in chrome. If you use Man().Man you will get undefined as well since this refers to the window object and the function Man() has no property Man. You could write
function Man(){
this.Man = "Peter";
return this.Man;
}
This returns the value Peter. If you want to have a property Man you could use a constructor function write
// set this.Man == window.Man to Peter
function Man() { this.Man = "Peter"; }
// create an constructor for each object Man
Man.prototype = { constructor: this.Man }
// create an object
var man = new Man();
// call his property which was set in the constructor of the prototype
man.Man;
Please ask for more help if anything is unclear.
Update as response to the comment
You can use a constructor without using prototype (see examples at mdn or this question if you use this syntax:
function Box(color) // Constructor
{
this.color = color;
}
var redBox = new Box("red");
var blueBox = new Box("blue");
redBox.color; // returns red
blueBox.color; // returns blue
To understand where this refers to you can take a look at understanding javascript this. In the box-example this refers to the new instance (object) of the "underlying class function". In function Man(){this.Man = "Peter"} the this refers to this.window. You can read more about protype in this book.