Why can't Promise.resolve be called as a function? - javascript

Something that is bugging me and my colleague. Consider the following...
const {map, compose} = require('ramda');
compose(
console.log,
map(Math.tan)
)([1,2,3]);
compose(
console.log,
map(v=>Promise.resolve(v))
)([4,5,6]);
compose(
console.log,
map(Promise.resolve)
)([7,8,9]);
As you would expect, the tan of 1, 2 and 3 are output and so are the promises resolving 3, 4 and 5. But my question is... why does the third break? Why doesn't Promise.resolve behave in the same way as any other function?
[ 1.5574077246549023, -2.185039863261519, -0.1425465430742778 ]
[ Promise { 4 }, Promise { 5 }, Promise { 6 } ]
/home/xxx/node_modules/ramda/src/internal/_map.js:6
result[idx] = fn(functor[idx]);
^
TypeError: PromiseResolve called on non-object
at resolve (<anonymous>)
at _map (/home/xxx/node_modules/ramda/src/internal/_map.js:6:19)
at map (/home/xxx/node_modules/ramda/src/map.js:57:14)
at /home/xxx/node_modules/ramda/src/internal/_dispatchable.js:39:15
at /home/xxx/node_modules/ramda/src/internal/_curry2.js:20:46
at f1 (/home/xxx/node_modules/ramda/src/internal/_curry1.js:17:17)
at /home/xxx/node_modules/ramda/src/internal/_pipe.js:3:27
at /home/xxx/node_modules/ramda/src/internal/_arity.js:5:45
at Object.<anonymous> (/home/xxx/b.js:20:6)
at Module._compile (module.js:569:30)

Promise.resolve refers to the resolve function without context object.
You want to call it with the proper context object. This can be done
by calling it on that context object, as in v => Promise.resolve(v), or
by creating a bound version of it, as in Promise.resolve.bind(Promise)
So, this would work:
compose(
console.log,
map(Promise.resolve.bind(Promise))
)([7,8,9]);
Remember that Javascript does not have classes. Functions have no owner. Objects can store functions in their properties, but that does not mean the function is owned by that object.
Another way is setting the context object explicitly, with Function#call or Function#apply:
function (v) {
var resolve = Promise.resolve;
return resolve.call(Promise, v);
}
Maybe it's best illustrated by focusing on something other than a method:
function Foo() {
this.bar = {some: "value"};
this.baz = function () { return this.bar; };
}
var f = new Foo();
var b = f.bar;
var z = f.baz;
here b refers to {some: "value"} without {some: "value"} magically "knowing" that f stores a reference to it. This should be obvious.
The same is true of z. It stores a function without that function "knowing" that f also references it. This should be just as obvious, in theory.
Calling z() will yield different results than calling f.baz(), even though the called function is the same one. Only the context is different.

When a function is called its this variable is dynamically allocated a value.
The resolve function cares what that value is.
The third part of your code passes the resolve function and then calls it without the context of the Promise object.
This means that this does not get allocated the value of Promise which the function needs.

Promise.resolve needs to be called with this being a Promise constructor (or subclass).
resolve = Promise.resolve;
resolve(null); // Error
resolve.call({}); // Error: Object is not a constructor
So change this line:
map(Promise.resolve)
to:
map(Promise.resolve.bind(Promise))

Related

Javascript: typeof says "function" but it can't be called as a function

I'm really puzzled with Javascript this time:
var x = Array.prototype.concat.call;
typeof x; // function
x(); // Uncaught TypeError: x is not a function
What on earth is going on here?
If it helps, I also noticed:
x([1,2],[3,4]) does not work either
toString also thinks it's a function:
Object.prototype.toString.call(x); // "[object Function]"
This also happens with Array.prototype.concat.apply.
When it is forced as an expression it also does not work:
(0, Array.prototype.concat.call)([1,2],[3,4]); // Same TypeError
Tested in Chrome and Node.
The error is misleading. x is a function, but it has lost the referenced function (concat), which throws an error
Running on firefox gives a more descriptive error
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Called_on_incompatible_type
What it's saying is that the call function has nothing its bound to.
In the same way that if you take an object like this:
const a = {
b: 2,
test() {
console.log('hi', this.b);
}
};
const c = a.test;
c();
You will get hi undefined as you've lost the relationship of the function to b.
You can fix this by either doing c.bind(a)() or c.call(a)
The call function behaves similarly. It is going to be the same for every function, and the pseudocode would look something like this:
class Function {
constructor(functionDefinition) {
this.functionDefinition = functionDefinition;
}
call(newThis, ...args) {
// take this.functionDefinition, and call it with `this` and `args`
}
}
Since you are extracting out the call function, it loses the function object it's associated with.
You can fix this by either binding concat to the function, or using call on call :-)
const a = []
const boundFn = a.concat.call.bind(a.concat)
console.log(boundFn([3], [1,2]));
// Or, you can use `call` to pass in the concat function
const callFn = a.concat.call;
console.log(callFn.call(a.concat, [4], [1,2]))

Curried JavaScript - calling

I am admittedly a beginner with JavaScript, but I need to piece together someone else's code and I am having trouble understanding the following function and how to call it in node.
const invoke = method => object => object[method]
This obviously is a function that takes a method that returns another function that takes an object that then returns object[method], but what exactly is the purpose? How would one use this? Thank you.
the way i see it is as the const states, it invokes a function stored in an object ,
as you mentionned, this can be broken down to :
const invoke = (method) => {
return (object) => {
return object[method] ;
}
}
the goal of this i believe is that you can call it ( like you're telling a story ) expressively and concisely : invoke the function a from the functions object. ( functionnal-programming )
from this article about functional programming
Functional programming is declarative rather than imperative, and
application state flows through pure functions. Contrast with object
oriented programming, where application state is usually shared and
colocated with methods in objects.
but the term invoke got me thinking about Immediately invoked functions, so the usage of the const invoke can be :
getting function from the object ( without executing it ) not to have to instantiate the whole object and having the function in a variable and maybe manipulate it's prototype.
calling the function ( with parenthesis ).
getting a property from an object.
immediately invoke a function in an object.
const myFns = {
'a' : function(x){
console.log(x || 'something to log when no params passed');
},
'b': {
username : 'Doe'
}
}
const invoke = method => object => object[method]
let myFunction = invoke('a')(myFns);
myFunction('hello from myFunction'); // call it or modify myFunction.prototype ... etc.
invoke('a')(myFns)('hello'); // simply call it
let user = invoke('b')(myFns); // get a property
console.log(user.username);
(invoke('a')(myFns))(); // immidiatly invoke the function
probalby to avoid eval() :P
The name 'invoke' suggests it should really be written like this:
const invoke = method => object => object[method]()
The () is the invocation. It's very general, so hard to say exactly how it would be used, but here's a silly example.
class Dog {
speak () { console.log('woof') }
}
var dogs = [ new Dog(), new Dog(), new Dog() ];
dogs.forEach( invoke( 'speak' ) );
-> 'woof'
-> 'woof'
-> 'woof'
It's a pretty common pattern to let an array method like forEach do the second call of a higher-order function like this.

How does function.apply.bind work in the following code?

So I get that an array of [200,599] is returned from the promise and the callback function inside spread is being passed into Function.apply.bind, but now I'm lost. How is the array of [200,599] split into x and y? How exactly does the apply.bind work?
function getY(x) {
return new Promise( function(resolve,reject){
setTimeout( function(){
resolve( (3 * x) - 1 );
}, 100 );
} );
}
function foo(bar,baz) {
var x = bar * baz;
// return both promises
return [
Promise.resolve( x ),
getY( x )
];
}
function spread(fn) {
return Function.apply.bind( fn, null );
}
Promise.all(
foo( 10, 20 )
)
.then(
spread( function(x,y){
console.log( x, y ); // 200 599
} )
)
.apply() is a method on function objects. Like so:
console.log(Math.max.apply(null, [1, 2, 3])); // 3
.apply() accepts two arguments, the context (what would become this inside of the target function) and an iterable of arguments (usually an array, but the arguments array like also works).
.bind() is a method on function objects. Like so:
const x = {
foo: function() {
console.log(this.x);
},
x: 42
}
var myFoo = x.foo.bind({x: 5});
x.foo(); // 42
myFoo(); // 5
.bind() takes a context (what would become this), and optionally, additional arguments, and returns a new function, with the context bound, and the additional arguments locked
Since .apply() is a function in on itself, it can be bound with .bind(), like so:
Function.prototype.apply.bind(fn, null);
Meaning that the this of .apply() would be fn and the first argument to .apply() would be null. Meaning that it would look like this:
fn.apply(null, args)
Which would spread the parameters from an array.
Spread takes a function and binds the apply method to, partially applying the null argument. So in short,
spread(fn)
is transformed to
args => fn.apply(null, args)
which is the same as using the ES6 spread syntax
args => fn(...args)
where the function got its name from.
If you want the long answer, remember what bind does:
method.bind(context, ...args1)
returns a function that works like
(...args2) => method.call(context, ...args1, ...args2)
In our case, method is apply, the context is fn and the first arguments are null, so the call
Function.apply.bind( fn, null )
will create a function that works like
(...args2) => (Function.apply).call(fn, null, ...args2)
which is equivalent to the fn.apply(…) call above, given that apply is the method inherited from Function.prototype in both accesses.
The spread function is just a utility function to convert an array, into parameters passed to a function. The apply is doing the converting, and the bind is binding it to the calling function so that the "this" context is connected to same function.
To see how spread is working in a simpler form ->
spread(function (x,y){console.log(x,y);})([1,2])
You will get the answer, 1 2, as 1 is passed to x, and 2 is passed to y.
So in your example your promise.all is returning an array of resolved promises.
These are then getting mapped to parameters to your function(x,y).
The reason it works is the "destructuring" nature of apply (if given an array of values, they would be provided spreaded to the function you use apply on).
Now back to your code when calling bind on apply, the value returned is a function which returns the same function provided to bind, the only thing different is when executed it would be called using apply (with an array as thisArg in your case), but it isn't going to be executed until you call it.
In your case when the promise has resolved, the function provided tothen woule be executed with an array of arguments provided by Promise resolution.
function spread(fn){
let boundedFn = fn.bind(fn)
return function(arg){
return boundedFn.apply(null,arg)
}
}
spread((x, y, c) => console.log(x, y, c))([1,2,3])
// or
Promise.resolve([6, 5]).then(spread((a, b) => console.log(a, b)))
The reason bind is provided (in your code) with null as second param is to prevent the array provided by the caller from being given to apply as its first param, which reserved for this.

How can I reference a `this` property within a method of `this`?

I append a services property to this:
function Client(){
this.services = {
'propertyName' : {}
};
and then append a method to this, in which I need to reference the services property of the instance of client:
function Client(){
this.services = {
'propertyName' : {}
};
this.someMethod = function () {
if (this.services['propertyName']) {
//do something
}
}
}
var clientName = new Client();
But this.services - line 6 is undefined. How can I use a property assigned to this in a method assigned to this? It seems like it should be possible because by the time that method is called by the constructor, the services property will exist for the object. Is this a language limitation? Is it possible? Should it be?
But this.services - line 6 is undefined.
That will depend entirely on how you call someMethod. If you call it like this:
clientName.someMethod();
...it'll be fine, because this within the call will be the object created by new Client that you've put the services property on. But in JavaScript, this is not a fixed thing with normal functions, it's set by how you call the function. So:
var f = clientName.someMethod;
f();
...would fail, because this wouldn't be the object you expect. (This isn't true of ES6's new "arrow" functions, which get this from where they're defined, not how they're called.)
You mostly see this when functions are used as callbacks:
doSomething(clientName.someMethod);
...because doSomething doesn't know what object to use as this.
You can fix it by using Function#bind:
doSomething(clientName.someMethod.bind(clientName));
or similarly:
var f = clientName.someMethod.bind(clientName);
f();
Function#bind creates a new function that, when called, will call the original with this set to the argument you give it.
Just to flesh out my ES6 comment above: In ES6, if you had:
function Client(){
this.services = {
'propertyName' : {}
};
this.someMethod = () => { // <== ES6 "arrow" function
if (this.services['propertyName']) {
//do something
}
}
}
...it wouldn't matter how you called someMethod, this would be what it is where that function was created. V. handy. :-)

javascript curry/partial function invokation for object functions

I want a 'curry' like function - this kind of thing
function invoker (fn) {
var slice = Array.prototype.slice,
args = slice.apply(arguments, [1]);
return function () {
return fn.apply(null, args);
};
}
But I want the user to be able to do
invoker(f)
or
invoker(foo.bar)
I cant find the correct magic incantation to do this. All the examples I see require the scope object to be passed in separately; which is error prone and not natural. IE
invokerx(foo.bar, foo)
IS there anyway to do this? I dont mind having 2 different functions
invokeG(f)
invokeO(foo.bar)
EDIT : clarification
'f' is a global scope function
'foo' is an object
'bar is a method on that object
IE I want this curry tool to work with'free' functions as well as with object functions.
Having to go
<curry function>(foo.bar,foo)
seems kinda clunky, I have have to say 'foo' twice
The first argument of apply is the this that is available to the function. Since you're passing null, this will get mapped to window.
The following modification will work:
function invoker (fn, target) {
var slice = Array.prototype.slice,
args = slice.apply(arguments, [2]);
if(typeof fn === 'string')
fn = (target || window)[fn];
return function () {
return fn.apply(target || null, args);
};
}
// Either will work:
invoker(foo.bar, foo);
invoker('bar', foo);
// Any of these will work:
invoker(escape, null);
invoker(escape, window);
invoker('escape', null);
invoker('escape', window);
UPDATE Added a slight change to add support for name passing so you don't have to pass the object name twice.
UPDATE 2 Since we're currying, we need there to always be two arguments.
You can't. When you do invoker(foo.bar), invoker has no way of knowing that the argument is a member function of foo. Functions do not store their "owner", and invoker is just passed a reference to a function.
The closest you can get is to use function.bind(), like this:
invoker(foo.bar.bind(foo))

Categories