i'm trying to create a JavaScript object named human with three methods walk, eat and talk, and i want to call it like this (no method should print any values): human.talk('hello').walk('home').eat('pizza').
I have this code:
var human = {
talk : function talk(t){
},
walk : function walk(w){
},
eat : function eat(e){
}
};
console.log(human.talk('hello').walk('home').eat('pizza'));
But i'm receiving Uncaught TypeError: Cannot call method 'walk' of undefined
Why??
Each function needs to return this if you want to be able to chain functions. You are getting the error because the function talk is returning undefined and you are essentially trying to call undefined.walk('home').
You cannot just chain calls like that. Did you mean to log all three results?
console.log(human.talk('hello'),human.walk('home'),human.eat('pizza'));
If you did want to have a "fluent" call chain, your functions all need to return this (so that you can proceed to call functions on it).
its not exactly clear what you are trying to achieve with the code above but from what I can see, there are two options:
A. you are trying to call all three functions and have console.log print the results of the functions in sequence, one after the other, ie you are using the (.) operate to concatenate the results of the function calls into one long string, in this case i would like to remind you that the concatenation operator in javascript, unlike, say php is + and not (.) so rather use this:
console.log(human.talk('hello') + walk('home') + eat('pizza'));
B. You actually want to call a chain for function calls. in which case i would like to remaind you that the . operator retrieves a property or method of an object ie the syntax is (object).(property), always the identifier or value before the operator should be an object. So, in order for you chain call to work, all your given function should return an object,(well, maybe except for the last one) in this case, the appropriate return value would be "this":
var human = {
talk : function(t){
return this;
},
walk : function(w){
return this;
},
eat : function(e){
return this;//or whatever here
}
};
Related
I was looking through the React source and stumbled across a requirement with var emptyFunction = require('fbjs/lib/emptyFunction');.
I looked at this function and was confused by what it does.
Here is the function
function makeEmptyFunction<T>(arg: T): (...args: Array<any>) => T {
return function() {
return arg;
};
}
const emptyFunction: (...args: Array<any>) => void = function() {};
In the comments, they give the following explanation which I was confused by:
This function accepts and discards inputs; it has no side effects.
This is primarily useful idiomatically for overridable function
endpoints which always need to be callable, since JS lacks a null-call
idiom ala Cocoa
I have never come across null call idiom and was hoping someone could clarify what this means and explain the purpose of this function in less technical language.
Hopefully this question will not get looked down on because it isn't exactly code related. Maybe it belongs somewhere else, if so I'm sorry.
When programming in JavaScript, we can take a function as a parameter to a certain operation. As an example, a function may have a callback which is invoked after some kind of event.
function doIt(callback) {
// some work
callback();
// more work
}
Now if this callback is an optional parameter and it's not provided, we will get Uncaught TypeError: callback is not a function error because callback is undefined. There are two solutions to this issue. The obvious one is checking the callback with an if statement. Another option is set an empty function as the default value of callback if it's not assigned. This approach is very useful and shines if we have multiple places which invoke the callback function. So we don't need to check it for undefined every time before calling it.
function doIt(callback) {
callback = callback || function(){};
// some work
callback();
// more work
}
Likewise, there are lots of use cases where we can have overridable functions variables. It's a common pattern to set these type of variables to empty function as the default value so that we can call them without worrying about whether those are assigned/overridden or not.
Also, in some special cases, it's useful to have functions which do nothing but return a particular value. makeEmptyFunction is used for creating such functions. Basically, it returns a function which does nothing but returns what ever the parameter pass to it.
emptyFunction.thatReturnsFalse = makeEmptyFunction(false);
As you can see in the file, above code generate an empty function which returns false value.
"null call idiom" is something we find in Objective-C/Cocoa programming. It basically allows you to call a method of an uninitialized object (null pointer) without giving any errors like in most of the other languages. I think that's what the author have tried to explain in the comment.
Since JavaScript doesn't have such language feature, we explicitly achieve it using empty functions. Some people call it no-op or noop and you can find similar helpers in other popular JavaScript libraries such as JQuery and AngularJS also.
I have module that returns an object to a callback with the structure of the following pseudocode:
module.exports=function(){
global.foo=function(){
var callbacks=Array.prototype.slice.call(arguments,1);
var conf=arguments[0];
return global[callbacks.shift()].apply(null,[conf,callbacks]);
}
global.bar=function(){
var callbacks=Array.prototype.slice.call(arguments,1);
var conf=arguments[0];
return global[callbacks.shift()].apply(null,[conf,callbacks]);
}
// This one is where i ran into trouble
global.foobar=function(){
var callbacks=Array.prototype.slice.call(arguments,1);
var conf=arguments[0];
// right here
if(callbacks.length===[].length){
return global[callbacks.shift()].apply(null,[conf,callbacks]);
}
}
var conf={'pseudo':'object'};
return global['foo'](conf,'foo','bar','foobar');
}
Everything works fine until foobar, and what happens is that when I get down to checking if there are anymore callbacks - because if their are, I want to call them - callbacks.length is 1 at this point. This didn't make sense to me, and I discovered that at that point callbacks actually equaled [[]]. I don't know why this is getting returned, so I guess I have two questions. Can anyone see why callbacks is equal to [[]]?
What I discovered along the way is that when using Strings called as functions in the global namespace - as in var bar='foo'; global[bar]() calls global.foo() - multiple brackets are ignored. So for example, global[[[[[[['foo']]]]]]] === global['foo']. Also weirdly enough (at least to me), the following:
// With
global.bar='foo';
global.foo=function(){return true;}
//the following
global[global[bar]]()
// throws a TypeError: undefined is not a function
None of that makes sense to me.
I recognize that this question ends up asking three questions, and is a bit disorganized, but frankly I'm a bit confused, and I'm not really sure how I want to ask what I want to know, so I just said everything.
My main questions is regarding the multiple brackets, and why that works.
Thanks
My main questions is regarding the multiple brackets, and why that
works.
The multiple brackets works only because it's trying to do a string conversion to get a property name. So, no matter how many nested arrays you have, it ends up calling .toString() on each array and since the inner array only has a single item that has a string in it, multiple .toString() calls just end up resolving to the inner string.
Here's a demo of the same concept in a browser:
window.foo = "hi"
document.write(window[[[[["foo"]]]]]);
For some further explanation:
["foo"].toString() === "foo";
So, then:
[["foo"].toString()].toString() === "foo"
But, if the outer .toString() is there, it is already driving things to a string so you can remove the inner .toString() and thus you get:
[["foo"]].toString() === "foo"
And, you can then nest it as many levels as you want as long as something on the outer level is driving it to a string.
And, since property names are always strings, when you do:
global[[[[[[['foo']]]]]]]
You're ultimately asking for a property name that can be looked up on the global object and since the property name is a string, that calls .toString() on the outer array. When the outer array goes to convert it's only item to a string, it asks that one item to convert itself to a string so this:
global[[[[[[['foo']]]]]]]
turns into this:
global[[[[[[['foo'].toString()].toString()].toString()].toString()].toString()].toString()]
Which hopefully explains why you end up with nothing more than this in the end:
global["foo"]
FYI, if you look at the ES5/ES6 spec for Array.prototype.toString(), it ends up calling array.join() which for a single element array just ends up doing a .toString() on that single element which is how it causes all the nested arrays to just call .toString() on themselves. The outer array calls .toString() on the first nested array which called .toString() on it's single item which is the next nested array and so on until it finally gets to the inner string which is returned back from all the .toString() calls. And, it matters not how many arrays deep it is nested.
Spec reference for Array.prototype.toString(): http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.tostring
Spec reference for Array.prototype.join() which is called by Array.prototype.toString(): http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.join
In your other scenario here:
// With
global.bar='foo';
global.foo=function(){return true;}
//the following
global[global[bar]]()
// throws a TypeError: undefined is not a function
None of that makes sense to me.
Here's what is going on in global[global[bar]]() one piece at a time:
bar resolves to the string 'foo'.
So, global[bar] resolves to global['foo'] which is your function.
But, then you try to do another global reference on it like this global[global[bar]], then you are essentially trying to do:
global[yourfunction]
or
global[global.foo]
That will try to convert yourfunction to a string and look up that property on the global object. That will be undefined. So, you will then try to do undefined() which is a TypeError because undefined is not a function.
What will work in this case is just:
global[bar]()
This doesn't work:
var s = '^foo';
console.log(['boot', 'foot'].some(s.match));
Uncaught TypeError: String.prototype.match called on null or undefined
But this does:
var s = '^foo';
console.log(['boot', 'foot'].some(function(i) { return i.match(s) }));
Why is this? I imagine somehow the String.prototype.match function is too "primitive" or something, but why exactly? Since I'm not using ES2015, the second version seems quite verbose. Is there an alternative?
EDIT
When I wrote the above, I actually got it backwards compared to my actual need, which was matching one string against a number of regexes. But thanks to the great answers and comments below, I get it: [/^foo/, /^boo/].some(''.match, 'boot').
Note: The value of this is determined by how the function is called! (exception: bound and arrow functions)
If you pass s.match to .some, then the function will be called with this set to the global object (e.g. window) not the string it "belongs" to.
I.e. it would be equivalent to this:
String.prototype.match.call(window, 'foo')
This cannot work because this has to refer to a string object.
You could solve this by binding the function to a specific this value:
['boot', 'foot'].some(s.match.bind(s));
Learn more about this:
MDN - this
You Don't Know JS: this or That?
How to access the correct `this` context inside a callback?
A function value in Javascript does not bring its object along with it. The value of s.match is a plain function value, with no knowledge that you happened to find it attached to s. In fact, no matter what String you access it through, it's always the same function value:
"foo".match === "bar".match
//= true
When you call a function through an object, Javascript sets this to that object for the duration of the function call. But as soon as anything comes between retrieving the function value and calling it, any object association is lost.
You can create a function that does remember a specific this value using bind, as in #Felix King's answer. someFunction.bind(someObject) has approximately the same meaning as function(arg1, arg2,...) { return someObject.someFunction(arg1, arg2,...); }, but it automatically handles the number of parameters properly.
When I reading this answer, find var g = f.call.bind(f);. I can't understand this with my first sight.
So does it has some direct meaning, and has some appropriate usage scenarios?
And further when you using call(or apply) or bind or both in chaining, what will happen? Is there some laws?
var g = f.call.bind(f);. I can't understand this with my first sight.
I assume you're familar with both the .call() and .bind() Function methods? Well, it binds the f.call method to the function f.
Notice that f.call is just Function.prototype.call, it doesn't matter that we access it as a property on f because we don't call it here.
So does it has some direct meaning?
It might become more obvious when we look at the ES6 equivalent:
(Function.prototype.call).bind(f) // or
(f.call).bind(f) // is basically
(...args) => f.call(...args) // or more clear
(ctx, ...args) => f.call(ctx, ...args)
Does it have some appropriate usage scenarios?
Well, now that you know what it does, yes. It can take a prototype method and transforms it to a static function that takes the instance as the first argument. An example:
function Example(n) { this.name = n; }
Example.prototype.display = function() { console.log(this.name); }
Example.display = Function.call.bind(Example.prototype.display);
var e = new Example;
e.display(); // is the same as
Example.display(e);
Are there any laws for further chaining call/apply/bind?
Yes: as always, only the last property in the chain is actually called as a method. In the above example, theres no difference between f.call.bind(…), Function.prototype.call.bind(…) or Function.call.apply.bind.call.bind(…) - it always calls bind on call.
However, by passing them as arguments to each other, you can do some crazy things which are more or less useful.
Good question. Let's start off by considering an example that's come up on StackOverflow before: mapping all the strings in an array to lowercase. Of course I can write
strings . map(function(string) { return string.toLowerCase(); })
but that seems a bit verbose. I'd rather write
strings . map(CALL_LOWERCASE_WITH_ELT_AS_THIS)
So I might try
strings . map(String.prototype.toLowerCase)
or, to use the shorter idiom some prefer
strings . map(''.toLowerCase)
because ''.toLowerCase is exactly equal to String.prototype.toLowerCase.
But this won't work, of course, because map passes each element to the specified function as its first argument, not as its this. Therefore, we need somehow to specify a function whose first argument is used to call some other function as its this. That, of course, is exactly what Function.call does:
function.call(context)
The first argument to call ("context") is used as the this when calling function.
So, problem solved? We ought to be able to just say:
strings . map(''.toLowerCase.call)
and people have tried this and then wonder why it didn't work. The reason is that even though we are passing call of toLowerCase as the callback to map, map still has no idea that the callback is supposed to be called with a this of ''.toLowerCase. We need to explicitly tell map which this to use to call the function, which in the case of map we can do with its second "context" argument:
strings . map(''.toLowerCase.call, ''.toLowerCase)
Actually, since call is the same on any function object, we can simplify this to just
strings . map(Function.call, ''.toLowerCase)
This works and gets the job done beautifully.
However, whereas map provides this second "context" argument to specify the this to call the callback with, that is not something we can depend on being available in all situations. We need a more general way to say "make a function which calls Function.call with some particular function as this".
That is exactly what bind does. It says "take a function and make another function which calls it with a particular this":
function.bind(context)
In our case, what we want to do is to "take the function Function.call and make another function which calls it with a this of ''.toLowerCase. That is simply
Function.call.bind(''.toLowerCase)
Now we can pass this to map without having to use the second argument:
strings . map(Function.call.bind(''.toLowerCase))
That works exactly the same as strings . map(Function.call, ''.toLowerCase), because in general map(fn, ctxt) is precisely equal to map(fn.bind(ctxt)).
The following breaks this down into a readable form, step by step:
Function . // From the Function object
call . // take the `call` method
bind( // and make a new function which calls it with a 'this' of
''.toLowerCase // `toLowerCase`
)
When this construct is specified as a callback, such as to map, it means:
Invoke call with the first argument passed in and ''.toLowerCase as this, which by virtue of the definition of call, means to call toLowerCase with that argument as this.
Some people prefer to simplify this a bit by saying
var call = Function.call;
var toLowerCase = ''.toLowerCase;
strings . map(call.bind(toLowerCase))
or, using the second argument provided by map, just
strings . map(call, toLowerCase)
which is almost readable as English: "map each string to the result of calling toLowerCase.
Another common, related use case would be specifying the callback in a then on a promise. Consider the following code:
promise . then(function(result) { result.frombulate(); })
That's fine, but it's a bit verbose. And then has no way to pass in a context to be used as this when invoking the success or failure handler. But with the above, we can now write:
promise . then(call.bind(frombulate))
There are other use cases for the call.bind idiom, but this is one of the most common ones: define a callback whose effect is to invoke some function with the parameter passed to the callback as its this.
With ES6 fat arrow functions, of course, I can write
promise . then(result => result.frombulate())
so there is relatively less advantage in the shorthand offered by call.bind(frombulate), and it is hard to deny that the fat-arrow version is more readable than that using bind.
The following question might be of interest too: Array.map and lifted functions in Javascript.
m.call.bind(m)
can be used as shorthand for:
function(x){return m.bind(x)()}
The former is the "point-free" form of the latter,
arguments are implicit. It would be useful with
list-operations like map(), making them shorter.
You can write stuff like:
let m = "".toUpperCase;
let fun = m.call.bind(m);
let see = ['a','b'].map(fun);
I saw these 2 basic ways of namespacing in JavaScript.
Using object:
var Namespace = { };
Namespace.Class1 = function() { ... };
Using function:
function Namespace() { };
Namespace.Class1 = function() { ... };
How do they differ? Thank you.
As others have pointed out, a function is an object so the two forms can be interchangeable. As a side note, jQuery utilizes the function-as-namespace approach in order to support invocation and namespacing (in case you're wondering who else does that sort of thing or why).
However with the function-as-namespace approach, there are reserved properties that should not be touched or are otherwise immutable:
function Namespace(){}
Namespace.name = "foo"; // does nothing, "name" is immutable
Namespace.length = 3; // does nothing, "length" is immutable
Namespace.caller = "me"; // does nothing, "caller" is immutable
Namespace.call = "1-800-555-5555" // prob not a good idea, because...
// some user of your library tries to invoke the
// standard "call()" method available on functions...
Namespace.call(this, arg); // Boom, TypeError
These properties do not intersect with Object so the object-as-namespace approach will not have these behaviours.
The first one declares a simple object while the second one declares a function. In JavaScript, functions are also objects, so there is almost no difference between the two except that in the second example you can call Namespace() as a function.
Well, if all you're doing us using that "Namespace" thing as a way to "contain" other names, then those two approaches are pretty much exactly the same. A function instance is just an object, after all.
Now, generally one would use a function like that if the function itself were to be used as a constructor, or as a "focal point" for a library (as is the case with jQuery).
They don't. Functions are "first class objects". All this means is that conceptually and internally they are stored and used in the same ways. Casablanca's point of one difference you can call it as a function is a good one though. You can also test for whether or not the class was defined through a function with the typeof operator.
typeof {}
returns "object"
typeof (function())
returns "function"