Function context after use with Meteor.bindEnvironment?

I have a problem with this code recently:

function doSth() { console.log(this); } const fWithMeteorEnv = Meteor.bindEnvironment(doSth); fWithMeteorEnv.call({}); // expect to see a plain object in console 

I expect to see a simple object in the console, but no, this is something else. Meteor.bindEnvironment prevent calling the returned function with a different context. Is there any way around this?

+6
source share
2 answers

I think that what you are trying to achieve is impossible, i.e. you will need to bind your context the moment you call Meteor.bindEnvironment . You can do this with .bind() , for example.

 const fWithMeteorEnv = Meteor.bindEnvironment(doSth.bind(context)); 

or you can pass the context as the third argument to Meteor.bindEnvironemnt() , for example.

 const fWithMeteorEnv = Meteor.bindEnvironment(doSth, null, context); 

The second argument is the exception callback.

+2
source

Meteor.bindEnvironment(func, onException, _this) takes 3 arguments, and the function returned by it is bound to the third argument. You need to bind it at the time of its creation, and using apply or call , it will pass arguments , but the this link will be redefined .

 function doSth() { console.log(this.foo); } const fWithMeteorEnv = Meteor.bindEnvironment(doSth, null, {foo: 'foo'}); fWithMeteorEnv.call({foo: 'bar'}); // will print 'foo' 

This is similar to what you would expect with Function.prototype.bind . You should not expect a call related function and have your this context as an argument.

 let f = function() { console.log(this); }.bind({foo:'foo'}); f.call({foo: 'bar'}); // will log `{foo: 'foo'}`. 

If you really need to set the this context for a function, you can wrap it and pass it as a parameter to the wrapper function (for example, use the first argument in the shell as the context for this source function).

If you need the call semantics of the return function, this can be quite confusing.

 /** * Wraps the function. * When the returned function is called, it sets the wrapped function `this` to its first * argument and passes it the rest of its arguments. */ function _wrapToMakeCallable(fn) { return function() { var _this = Array.prototype.shift.apply(arguments); fn.apply(_this, arguments); } } /** * This function wraps the boundWithEnvironment function and maps the arguments such * that it can be `call`ed or `apply`-ed as normal, using `wrapper`. */ function callableWrapAsync(fn) { const bound = Meteor.bindEnvironment(_wrapToMakeCallable(fn)); return function() { Array.prototype.splice.call(arguments, 0, 0, this); bound.apply(this, arguments); } } function doSth() { console.log(this.foo); } Meteor.startup(function() { const fWithMeteorEnv = Meteor.bindEnvironment(doSth, null, {foo: 'foo'}); fWithMeteorEnv.call({foo:'bar'}); // will print 'foo' const callable = callableWrapAsync(doSth); callable.call({foo:'bar'}); // will print 'bar' }); 
+2
source

Source: https://habr.com/ru/post/1014078/


All Articles