5 ms·
`this` is hard to learn. No it isn't. Its a function argument that is implicitly passed "left of the dot". Whatever object that function was attached to when y
by spion 9y ago
`this` is hard to learn.
No it isn't. Its a function argument that is implicitly passed "left of the dot". Whatever object that function was attached to when you call it? Thats the object thats gonna become the `this` argument.
Normal arguments, you pass them like so: `someFunction(normalArgument1, normalArgument2)`
The argument `this` you pass it like so: `thisArgument.someFunction(normalArgument1, normalArgument2)`
From this it immediately becomes clear why you can't pass that function away by itself. When whoever got it calls it, its going to have nothing "left of the dot" to call it with.
Done, `this` explained.
- katastic 9y agoYeah, if you can't grasp 'this', good luck figuring out delegates. (Note: Some/many languages call these "Closures") 'this' is just a context pointer. classes don't actually store their functions (except virtual ones). class A{ int data; void method1(int input){data = input;} } A my_instance; is actually struct A {int data;} method1_for_struct_A(A *context, int input){ context->data = input; } //normal local function A my_instance; and this: my_instance.method1(3); becomes this: method1_for_struct_A(my_instance, 3); //send a pointer to the class we're operating on And once you understand that, delegates are easy, because they're just... sending the context pointer around. So in D: //note: global function, NOT apart of any class. delegate void my_function(int input) { data = input; //where is data coming from? // the surrounding context. } void my_test_function() { int data = 2; my_function(3); // is a delegate and gets implicitly sent the context //pointer for my_test_function, and now, it can access data. // Note this is a RUN-TIME adjustable function. Delegates can be passed // around. } and internally my_function is actually (note the pattern): void my_function(context_pointer, int input) { context_pointer.data = input; } and the compiler implicitly sends the context with it: my_function(3) becomes my_function(my_test_function_context, 3); So basically, delegates are just an extension of what classes already use under-the-hood. Delegates are "fat" function pointers. Function pointers point to a function, and the "fat" pointer includes an additional "context" pointer to the surrounding data frame so you can dereference it to access the surrounding data. You can do all of this in plain C if you don't mind writing all the boilerplate code yourself. Virtual functions are similar to delegates. The class actually contains the function pointer / delegate instead of re-writing it at compile-time. Which allows them to be overridden at run-time. Whereas "this" usually means you can figure it out statically, at compile-time, so the function call is a pure function call and doesn't incur the penalty of looking up a pointer for the virtual call. I bet I'm probably missing something or slightly off here or there, so someone feel free to chime in and correct me. Consider the code pseudo-code. I might have flipped something from memory.
- toomim 9y agoIt's not that simple. You've mentioned only one of the possible meanings of `this`: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... In the global execution context (outside of any function), this refers to the global object whether in strict mode or not. // In web browsers, the window object is also the global object: console.log(this === window); // true a = 37; console.log(window.a); // 37 this.b = "MDN"; console.log(window.b) // "MDN" console.log(b) // "MDN" Inside a function, the value of this depends on how the function is called. == Simple call == Since the following code is not in strict mode, and because the value of this is not set by the call, this will default to the global object, which is "window" in a browser. function f1() { return this; } // In a browser: f1() === window; // true // In Node: f1() === global; // true In strict mode, however, the value of this remains at whatever it was set to when entering the execution context, so, in the following case, this will default to undefined: function f2() { 'use strict'; // see strict mode return this; } f2() === undefined; // true So, in strict mode, if this was not defined by the execution context, it remains undefined. == The bind method == ECMAScript 5 introduced Function.prototype.bind. Calling f.bind(someObject) creates a new function with the same body and scope as f, but where this occurs in the original function, in the new function it is permanently bound to the first argument of bind, regardless of how the function is being used. function f() { return this.a; } var g = f.bind({a: 'azerty'}); console.log(g()); // azerty var h = g.bind({a: 'yoo'}); // bind only works once! console.log(h()); // azerty == Arrow functions == In arrow functions, this retains the value of the enclosing lexical context's this. In global code, it will be set to the global object: var globalObject = this; var foo = (() => this); console.log(foo() === globalObject); // true Note: if thisArg is passed to call, bind, or apply on invocation of an arrow function it will be ignored. You can still prepend arguments to the call, but the first argument (thisArg) should be set to null. No matter what, foo's this is set to what it was when it was created. The same applies for arrow functions created inside other functions: their this remains that of the enclosing lexical context. == As an object method == When a function is called as a method of an object, its this is set to the object the method is called on. In the following example, when o.f() is invoked, inside the function this is bound to the o object. var o = { prop: 37, f: function() { return this.prop; } }; console.log(o.f()); // 37 Note that this behavior is not at all affected by how or where the function was defined. In the previous example, we defined the function inline as the f member during the definition of o. However, we could have just as easily defined the function first and later attached it to o.f. Doing so results in the same behavior: var o = {prop: 37}; function independent() { return this.prop; } o.f = independent; console.log(o.f()); // 37 This demonstrates that it matters only that the function was invoked from the f member of o. Similarly, the this binding is only affected by the most immediate member reference. In the following example, when we invoke the function, we call it as a method g of the object o.b. This time during execution, this inside the function will refer to o.b. The fact that the object is itself a member of o has no consequence; the most immediate reference is all that matters. == "this" on the object's prototype chain == The same notion holds true for methods defined somewhere on the object's prototype chain. If the method is on an object's prototype chain, this refers to the object the method was called on, as if the method were on the object. == "this" with a getter or setter == Again, the same notion holds true when a function is invoked from a getter or a setter. A function used as getter or setter has its this bound to the object from which the property is being set or gotten. == As a constructor == When a function is used as a constructor (with the new keyword), its this is bound to the new object being constructed. While the default for a constructor is to return the object referenced by this, it can instead return some other object (if the return value isn't an object, then the this object is returned). == As a DOM event handler == When a function is used as an event handler, its this is set to the element the event fired from (some browsers do not follow this convention for listeners added dynamically with methods other than addEventListener). == In an in–line event handler == When code is called from an in–line on-event handler, its this is set to the DOM element on which the listener is placed: <button onclick="alert(this.tagName.toLowerCase());"> Show this </button> The above alert shows button. Note however that only the outer code has its this set this way: <button onclick="alert((function() { return this; })());"> Show inner this </button> In this case, the inner function's this isn't set so it returns the global/window object (i.e. the default object in non–strict mode where this isn't set by the call).
- munificent 9y ago> No it isn't. Its a function argument that is implicitly passed "left of the dot". That is true in JavaScript, but not in other languages that also have "this" and closures. So the confusion comes from two issues: 1. JavaScript is inconsistent with other languages, and 2. It's not at all clear that JavaScript's semantics are actually good. In other languages where "this" is not loosely bound, there is next-to-no confusion around them and no problems, so the evidence is there that the semantics JavaScript chose aren't user-friendly. The reason JS has those semantics is because it (at the time) had no way to distinguish between a method declaration (where this should be dynamically bound) and a function declaration (where this should be lexically bound). Other languages with class syntax don't have that problem. JavaScript does have class syntax now, but changing the semantics of how this works would have been very difficult this many years later.
- spion 9y agoAll languages have different semantics. Otherwise they would've been one language. Python has an explicit self that is unbound. Other languages have it implicit and bound... Etc
- twic 9y agoWhat do you mean by "unbound"? Some Python: >>> class Foo: >>> def __init__(self, x): self.x = x ... ... def bar(self): print('x =', self.x) ... ... >>> f = Foo(23) >>> b = f.bar >>> b() x = 23 Note that when you extract the method from the object as a callable, it hangs onto the right self. Same deal as Java: class Foo { private int x; Foo(int x) { this.x = x; } void bar() { System.out.println("x = " + x); } } public static void main(String[] args) { Foo f = new Foo(23); Runnable b = f::bar; b.run(); // prints x = 23 }
- spion 9y agoI meant "bound", sorry. Funny that you mention "::" in Java. ES7/ES8 was going to have a bind operator "::" that extracts a bound method with a slightly different syntax. i.e. `::f.bar`
- ryanmarsh 9y agoCrockford says he doesn't use `this` and classes were the worst thing that could have been added to JavaScript.