2

I want to know if it is possible to somehow "bind" a javascript arrow function to an instance of the prototype to which it is scoped.

Basically, I want to get an instance variable from a prototype using an arrow function. I know this cannot be done by arrow function alone, but I am curious if it is possible to also bind this arrow function to the instance scope before assigning it. Something along the idea of:

String.prototype.myFunction = (() => {
    console.log(this.toString());
}).naiveBindNotionICantDescribe(String.prototype);

which would be equivalent to:

String.prototype.myFunction = function() {
    console.log(this.toString());
};

I am curious because I am trying to see if javascript arrow functions can completely replace javascript functions if you understand them well enough and are clever with them, or if there are things which are absolutely impossible to accomplish without keyword "function", even in clever ways.

Here is an example of what I mean:

/* anonymous self-contained demo scope. */
{
    /**
     * example #1: using function to reach into instance variable via prototype 
     * anonymous scope.
     */
    {
        String.prototype.get1 = function() {
            return this.toString();
        };
        console.log('hello'.get1());
    }

    /** 
     * example 2: what I want to do but can't express in a way that works.
     * This does not work.
     * anonymous scope.
     */
    {
        String.prototype.get2 = () => {
            return this.toString();
        };

        console.log('hello'.get2());  
    }  
}

Is this possible to do, or are functions absolutely necessary to reach into instance variable and there is no way to circumvent this?

Apparent Solutions:

  1. wrapper magicBind (Thanks Thomas)

code:

var magicBind = (callback) => function() { 
    return callback(this);
};
String.prototype.get = magicBind((self) => {
    return self.toString();
});
console.log('hello'.get());
  1. function converter from "fat arrow" to "function", (inspired by Thomas's answer)

code:

Function.prototype.magicBind2 = function() {
    var self = this;

    return function() {
        return self(this);
    }
};

String.prototype.get2 = ((self) => {
    return self.toString();
}).magicBind2();

console.log('hello'.get2());
  1. First solution without explicit use of 'function', which refers to "Function" constructor as (() => {}).constructor to avoid using the word "function" or "Function".

code:

var regex = /\{([.|\s|\S]+)\}/m;

String.prototype.get = (() => {}).constructor(
    (() => {
        return this;
    }).toString().match(regex)[0]
);

console.log('hello, world'.get());

Both solutions so far allow burial of "function" keyword while allowing accessing local scope.

Dmytro
  • 5,068
  • 4
  • 39
  • 50
  • 2
    Just 1 question: why would you replace every function with the fat arrow syntax version? Do you want to lose compatibility? – Bálint Aug 06 '16 at 22:13
  • 2
    fat-arrows have no own `this` or `arguments`-object. So you can't completely replace functions with fat-arrows. Imo. their main purpose is to act as callback-functions. – Thomas Aug 06 '16 at 22:14
  • I want to understand if it is possible to do. I am contemplating if javascript can exist without "function" keyword. Yes it's horrible for compatibility, but if you understand how they relate and they can be expressed in terms of one another, you can easily just translate arrow functions into functions by writing your own parser(and vice versa). – Dmytro Aug 06 '16 at 22:15
  • @Thomas that's not true. While the fat arrow does not have "this", javascript does have means to attach it to "this" during assignment via bind/apply/call/etc. My problem is that I have no idea what it means to get "this" of a prototype outside "function" scope. I am curious if there is a clever way to achieve this behavior, or if it is indeed impossible since you can't find out what "this" is to bind to it. – Dmytro Aug 06 '16 at 22:17
  • 1
    @Dmitry — No. `bind`/`apply`/`call`/etc have no effect on arrow functions. – Quentin Aug 06 '16 at 22:20
  • 1
    @Dmitry The `this` you see/use inside the fat arrow is a closure, you enclosed the `this`-variable from the surrounding context. It has nothing to do with the actual (fat-arrow-)function-call. Same would be for `arguments`. – Thomas Aug 06 '16 at 22:23
  • @Thomas I was hoping to do some magic involving passing the instance as an argument to the arrow function and using this instance "self" in place of "this". Something along the lines of http://hastebin.com/baxadaxoli.coffee but without the "function". eg, pass the "self" during assignment without creating a function via some magicBind operation. – Dmytro Aug 06 '16 at 22:28
  • that's not magic, that's just straight forward. `var log = (self, ...args)=>{ console.log(self, args) }` `log(this, 1, 2, 3)`. – Thomas Aug 06 '16 at 22:36
  • To clarify it: `this` only makes sense in the context of functions. It is just an implicit parameter, which isn't part of the formal parameters of a function. There are two ways to bind `this` within functions: Dynamically or statically (lexically). Arrow functions use the latter. Since a static `this` is immutable once the arrow is defined, arrow functions just inherit it from their definition context. –  Aug 08 '16 at 09:14
  • Possible duplicate of [Arrow function vs function declaration / expressions: Are they equivalent / exchangeable?](http://stackoverflow.com/q/34361379/1529630) – Oriol Aug 09 '16 at 01:49

3 Answers3

3

No. Lexically binding the this value is the point of arrow functions.

They are not a general replacement for function declarations and function expressions.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • 2
    That's technically not the point of fat arrow functions. That was only a feature added later in the developement. They main purpose is to be a syntatic sugar for functions, but they are mostly used where you want to access the parent object in the callback. – Bálint Aug 06 '16 at 22:17
  • So are you saying that it is impossible, or are you saying that this isn't how they should be used. – Dmytro Aug 06 '16 at 22:20
  • 3
    It's impossible. If it wasn't, I'd have said "Yes, but you shouldn't". – Quentin Aug 06 '16 at 22:20
0

I know this cannot be done by arrow function alone, but I am curious if it is possible to also bind this arrow function to the instance scope before assigning it.

Exactly, it can be done alone, but you can make this be the desired value... by wrapping it inside a normal function:

String.prototype.get2 = function() {
  return (() => this.toString())();
};
console.log('hello'.get2());

But at that point the arrow function becomes superfluous.

Oriol
  • 274,082
  • 63
  • 437
  • 513
0

I was hoping to do some magic involving passing the instance as an argument to the arrow function and using this instance "self" in place of "this". Something along the lines of hastebin.com/baxadaxoli.coffee but without the "function". eg, pass the "self" during assignment without creating a function via some magicBind operation.

var magicBind = (callback) => function (...args) {
    'use strict';
    return callback(this, args);
}

var log = (self, args) => {
  console.log('this: %o args: %o', self, args);
};

String.prototype.log = magicBind( log );

'hello'.log();

enough magic? ;)

Edit: but still, why do you insist on using fat arrows. Even if you have to jump through loops to achieve what you want. Just to scratch off a few characters from you .min.js-file

/* log was more appropriate than get,

and it makes no sense to console.log() the result of a function that has no return-value; even less if the only purpose of that function is calling console.log() itself */

Everettss
  • 15,475
  • 9
  • 72
  • 98
Thomas
  • 11,958
  • 1
  • 14
  • 23
  • I just came to a similar conclusion myself: http://hastebin.com/fanowawebi.coffee, except I struggled avoiding having to put the name inside it rather than setting the prototype explicitly how i originally wanted. If such a construct was built into javascript, then you could just convert any fat arrow to 'function' without using 'function'. Actually I thing this is exactly what I want: http://hastebin.com/mikipuwupe.coffee even though it is a very strange of phrasing it, especially with the part self(this). This way the it behaves similar to bind, rather than outer function. – Dmytro Aug 06 '16 at 23:30
  • I am still curious if it is truly impossible without using "function", but with this, you can bury the "function" keyword away in implementation and still recover it when necessary. – Dmytro Aug 06 '16 at 23:39
  • No, it's not. That's the point all across the answers on this question. Fat arrows don't have (their own) this-objects. And this doesn't behave like `bind()` at all. Bind locks one passed this-object in place, whereas this code propagates the passed this-object on each function-call as an function-argument to some callback. But still, why do you insist in doing this? no need to write `function` may seem nice at first, until you realize that you have to write `(...).magicBind2()` instead, plus you complicate your code, and you restrict your possibilities – Thomas Aug 06 '16 at 23:48
  • I know that. I was curious if an implementation of "magicBind" already exists under a different name, or can be derived from existing functions that do not use "function". If there isn't than indeed it is impossible without first creating a way to transform fat arrow to function, as done in existing solutions(after which, the keyword function is no longer "necessary" as long as you keep implementation buried(and your code itself does not contain the keyword function)). – Dmytro Aug 06 '16 at 23:53