Bind function without thisArg

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Bind function without thisArg

Sultan
Consider the following example:

var foo = (function(a) { console.assert(this === obj) }).bind(undefined, 1)
var obj = {foo: foo}

Calling foo from obj:

obj.foo(1)

Would result in an assertion. How does one go about preserving the this reference of the caller. That is i want to use .bind to only bind "arguments" and not "thisArg".



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Bind function without thisArg

Ranando King
Bind is just a wrapper function provided by the engine. You can always create your own:

```js
function myBind(fn, ...args) {
  let retval = Object.defineProperties(function(...a) {
    console.assert(typeof(fn) == "function");
    return fn(...args, ...a)
  }, {
    name: {
      configurable: true,
      value: fn.name
    },
    length: {
      configurable: true,
      value: fn.length
    },
    prototype: {
      configurable: true,
      writable: true,
      value: fn.prototype
    }
  });
}
```

This should apply your bound arguments before any arguments supplied by the caller without affecting the context object.

On Sun, Jan 13, 2019 at 11:39 PM Sultan <[hidden email]> wrote:
Consider the following example:

var foo = (function(a) { console.assert(this === obj) }).bind(undefined, 1)
var obj = {foo: foo}

Calling foo from obj:

obj.foo(1)

Would result in an assertion. How does one go about preserving the this reference of the caller. That is i want to use .bind to only bind "arguments" and not "thisArg".


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Bind function without thisArg

Ranando King
oops.... forgot to return retval!

On Mon, Jan 14, 2019 at 12:01 AM Ranando King <[hidden email]> wrote:
Bind is just a wrapper function provided by the engine. You can always create your own:

```js
function myBind(fn, ...args) {
  let retval = Object.defineProperties(function(...a) {
    console.assert(typeof(fn) == "function");
    return fn(...args, ...a)
  }, {
    name: {
      configurable: true,
      value: fn.name
    },
    length: {
      configurable: true,
      value: fn.length
    },
    prototype: {
      configurable: true,
      writable: true,
      value: fn.prototype
    }
  });
}
```

This should apply your bound arguments before any arguments supplied by the caller without affecting the context object.

On Sun, Jan 13, 2019 at 11:39 PM Sultan <[hidden email]> wrote:
Consider the following example:

var foo = (function(a) { console.assert(this === obj) }).bind(undefined, 1)
var obj = {foo: foo}

Calling foo from obj:

obj.foo(1)

Would result in an assertion. How does one go about preserving the this reference of the caller. That is i want to use .bind to only bind "arguments" and not "thisArg".


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Bind function without thisArg

Jordan Harband
In reply to this post by Ranando King
```
var foo = function(a) { console.assert(this === obj) };
var obj = { foo() { return foo.apply(this, arguments); } };
```
?

On Sun, Jan 13, 2019 at 10:01 PM Ranando King <[hidden email]> wrote:
Bind is just a wrapper function provided by the engine. You can always create your own:

```js
function myBind(fn, ...args) {
  let retval = Object.defineProperties(function(...a) {
    console.assert(typeof(fn) == "function");
    return fn(...args, ...a)
  }, {
    name: {
      configurable: true,
      value: fn.name
    },
    length: {
      configurable: true,
      value: fn.length
    },
    prototype: {
      configurable: true,
      writable: true,
      value: fn.prototype
    }
  });
}
```

This should apply your bound arguments before any arguments supplied by the caller without affecting the context object.

On Sun, Jan 13, 2019 at 11:39 PM Sultan <[hidden email]> wrote:
Consider the following example:

var foo = (function(a) { console.assert(this === obj) }).bind(undefined, 1)
var obj = {foo: foo}

Calling foo from obj:

obj.foo(1)

Would result in an assertion. How does one go about preserving the this reference of the caller. That is i want to use .bind to only bind "arguments" and not "thisArg".


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Bind function without thisArg

Sultan
The use case was to use bind to avoid closures such that "foo" is attached to an object on demand.

var obj = {}
// some place else
obj.foo = fn.bind(, 1, 2, 3)

Where the function "fn" relies on this being the "obj" it is attached to, this considering that calling a bound functions with:

fn.call(thisArg)

Doesn't change the thisArg.

On Mon, Jan 14, 2019 at 9:27 AM Jordan Harband <[hidden email]> wrote:
```
var foo = function(a) { console.assert(this === obj) };
var obj = { foo() { return foo.apply(this, arguments); } };
```
?

On Sun, Jan 13, 2019 at 10:01 PM Ranando King <[hidden email]> wrote:
Bind is just a wrapper function provided by the engine. You can always create your own:

```js
function myBind(fn, ...args) {
  let retval = Object.defineProperties(function(...a) {
    console.assert(typeof(fn) == "function");
    return fn(...args, ...a)
  }, {
    name: {
      configurable: true,
      value: fn.name
    },
    length: {
      configurable: true,
      value: fn.length
    },
    prototype: {
      configurable: true,
      writable: true,
      value: fn.prototype
    }
  });
}
```

This should apply your bound arguments before any arguments supplied by the caller without affecting the context object.

On Sun, Jan 13, 2019 at 11:39 PM Sultan <[hidden email]> wrote:
Consider the following example:

var foo = (function(a) { console.assert(this === obj) }).bind(undefined, 1)
var obj = {foo: foo}

Calling foo from obj:

obj.foo(1)

Would result in an assertion. How does one go about preserving the this reference of the caller. That is i want to use .bind to only bind "arguments" and not "thisArg".


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Bind function without thisArg

T.J. Crowder-2
Although this is easy enough to implement in userland, frankly so was `bind`. I'd say it comes up often enough to consider. PrototypeJS (remember PrototypeJS?) called it `curry`.

I'd think the specification changes for it would be minimal as well, basically A) Allowing Empty as boundThis in BoundFunctionCreate and [[BoundThis]] on functions; B) Updating [[Call]] on Bound Functions to use thisArgument when boundThis is Empty; creating a new `Function.prototype` method (`curry` would be the obvious -- and almost certainly **not** websafe -- name) to call BoundFunctionCreate with Empty for boundThis.

But I'd be interested to know how difficult it is for JavaScript engines to implement, since Empty is largely a spec-level concept and it's valid (in strict mode) to use `null` and `undefined` as boundThis...

-- T.J. Crowder

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Bind function without thisArg

Andrea Giammarchi-2
It's not so easy to implement in user land, not because it's difficult to do so:

```js
Function.prototype.bindArgs = (...args) => {
  const fn = this;
  return function (...moar) {
    return fn.apply(this, args.concat(moar));
  };
};
```

rather because of the bloat it produces once transpiled: https://bit.ly/2SULtFZ

To avoid bloat and `arguments` leaking here and there, one must write something like:

```js
function slice() {
  const arr = [];
  for (let {length} = arguments, i = +this; i < length; i++)
    arr.push(arguments[i]);
  return arr;
}

Function.prototype.bindArgs = function () {
  const args = slice.apply(0, arguments);
  return function () {
    const moar = slice.apply(0, arguments);
    return fn.apply(this, args.concat(moar));
  };
};
```

which is still a hell of a boilerplate compared to a native `const ba = fn.bindArgs.apply(fn, arguments);` or `fn.bindArgs(...arguments)` for short.

+1 for having this in core


On Mon, Jan 14, 2019 at 12:48 PM T.J. Crowder <[hidden email]> wrote:
Although this is easy enough to implement in userland, frankly so was `bind`. I'd say it comes up often enough to consider. PrototypeJS (remember PrototypeJS?) called it `curry`.

I'd think the specification changes for it would be minimal as well, basically A) Allowing Empty as boundThis in BoundFunctionCreate and [[BoundThis]] on functions; B) Updating [[Call]] on Bound Functions to use thisArgument when boundThis is Empty; creating a new `Function.prototype` method (`curry` would be the obvious -- and almost certainly **not** websafe -- name) to call BoundFunctionCreate with Empty for boundThis.

But I'd be interested to know how difficult it is for JavaScript engines to implement, since Empty is largely a spec-level concept and it's valid (in strict mode) to use `null` and `undefined` as boundThis...

-- T.J. Crowder
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Bind function without thisArg

Boris Zbarsky
On 1/14/19 9:47 AM, Andrea Giammarchi wrote:
> rather because of the bloat it produces once transpiled:

Hold on.

The transpiling is necessary because of lack of what features in
implementations?

And what is the set of implementations that will lack those features but
support bindArgs?

(None of that is an argument against having bindArgs in core per se; I'm
just trying to understand the transpiling issue here.)

-Boris
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Bind function without thisArg

Andrea Giammarchi-2
The transpilation is what everyone publishing Web Apps/pages do these days, it's not needed but most developers don't care, they mostly use whatever bundler default is there.

The **main** lack of ECMAScript feature is a method that is not based on new syntax, doesn't leak arguments, and transform these into an Array.

My proposed `slice.apply(index, arguments)` is still not used by transopilers to solve forever in one place the issue so that production code is full of unnecessary boilerplate every single time some dev uses rest parameters for any callback.

If there was a method, not based on new syntax, able to be called through `fn.apply(fn, arguments)` so that arguments wouldn't leak, and transpilers can use a single polyfill as entry point to provide that ability, no extra boilerplate would be ever need in production code.

I hope what I've said makes sense 👋




On Mon, Jan 14, 2019 at 4:49 PM Boris Zbarsky <[hidden email]> wrote:
On 1/14/19 9:47 AM, Andrea Giammarchi wrote:
> rather because of the bloat it produces once transpiled:

Hold on.

The transpiling is necessary because of lack of what features in
implementations?

And what is the set of implementations that will lack those features but
support bindArgs?

(None of that is an argument against having bindArgs in core per se; I'm
just trying to understand the transpiling issue here.)

-Boris
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss