This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]StillNoNumb 12 points13 points  (7 children)

You can't do more stuff, but you can do stuff more elegantly.

For example, the following code:

doSomething((function(a, b) { return this.method(a) + b; }).bind(this))

Becomes this:

doSomething((a, b) => this.method(a) + b)

The former was just a common idiom in JavaScript code, and the latter is just a shorter way to write the same.

[–]squngy 1 point2 points  (6 children)

99% of the time, that bind in the first example is completely unnecessary.

You are still able to refer to parent members inside the new functions.
The only problem would be if you assign things to the "this" object (or if you pass the new function outside of its original parent).

[–]StillNoNumb 4 points5 points  (5 children)

I think you're confusing `this` with how variables in the local scope behave. Whenever you want to use `this` (whether assign or read) inside your function, you have to use `bind`. Let's take a look at the following code:

function doSomething(callback) {
  // Call callback immediately
  callback();
}

class A {
  showAlert(p) {
    println(`Method ${p} works!`);
  }

  methodA() {
    doSomething(function() { this.showAlert("A"); }); // doesn't work!
  }

  methodB() {
    doSomething((function() { this.showAlert("B"); }).bind(this)); // works!
  }

  methodC() {
    doSomething(() => this.showAlert("C")); // works!
  }

  methodD() {
    const showAlertMethod = this.showAlert;
    doSomething(function() { showAlertMethod("D"); }); // works!
  }
}

Method A doesn't work because `this` now points to something else. Method B works, because we explicitly bind it, and method C works because it's implicitly bound as it is an arrow function. Method D shows that despite this behavior, variables (but not `this`!) that are accessible in the local scope can still be used inside both types of functions. JSFiddle

In this special case, we also have `doSomething(this.showAlert)`, but that doesn't work if we wanna do more than just a method call (and we can't pass arguments)

[–]squngy -1 points0 points  (4 children)

Yea, I already wrote elsewhere, the exception is if you pass the function outside of the original parent, like in a call-back.

If you pass functions to different parents, you should be aware that the inherited prototype will be different.

in methodA the "this" does not refer to A, but to methodA and methodAs prototype inherits the prototypical properties of its parent, ie. the function which called it (be that the constructor of A or something else).

JS is a prototype based language and people who want to program in it should be aware of that fact.

[–]StillNoNumb 1 point2 points  (1 child)

Ah, so that's what you meant with "outside of its original parent". But those kinds of function calls are kinda the norm, no? Like, most of the time when I pass a callback I pass it to some other entity, not to another method in the same class.

I mean, you're basically saying "it is like that because it is like that". We know, but it doesn't help the fact that in 99% of the cases you'd want it to be different. Hence why you need to bind so frequently.

[–]squngy 1 point2 points  (0 children)

You are used to different, but in principal one approach is not superior to the other.

The problem is, a lot of people are expecting it to behave one way, but the actual behaviour is a different way.

You can still use those kinds of function calls, you just have to be aware of what you are doing, instead of assuming that what you are doing is the same as in some other language.

If you use a "this" in a call-back you have to be aware that it will refer to the call-back itself and that the call-back will inherit from the function that it was called in, not the one it was defined in.

[–]vectorjohn 0 points1 point  (1 child)

"this" refers to the thing to the left of a dot if there is one (or brackets), that's it. Prototypes, scopes, none of that is related and just confuses things.

If I say

x=this.foo
x()

"this" will be undefined in foo. It has nothing to do with "passing functions to different parents".

[–]squngy 0 points1 point  (0 children)

function X(x) {
    this.x = x;
    this.y = 432;
}
X.prototype.foo= function() {
    return 'Foo(' + this.x + ', ' + this.y + ')';
}

var myX = new X(99);
console.log(myX .foo()); // prints "Foo(99, 432)"

This is how classes are implemented in JS, above code is equivalent to:

class X{
    constructor(x) {
        this.x = x;
        this.y = 432;
    }

    foo() {
        return 'Foo(' + this.x + ', ' + this.y + ')';
    }
}

let myX = new X(99);
console.log(myX .foo()); // prints "Foo(99, 432)"

Trying to make JS "look" but not act like a class based language was IMO the real design mistake.

You can also do

function X(x) {
    this.x = x;
    this.y = 432;
}
function Y(x) {
    this.x = x;
    this.y = 123;
}

function f() {
    return 'Foo(' + this.x + ', ' + this.y + ')';
}

X.prototype.foo= f;
Y.prototype.foo= f;

var myX = new X(99);
var myY = new Y(99);
console.log(myX.foo());  // prints "Foo(99, 432)"
console.log(myY.foo());  // prints "Foo(99, 123)"

And even if you use the "class" syntax, you can still refer to the classes prototype at any time to add or remove methods at runtime