JavaScript Object Constructors [duplicate] - javascript

This question already has answers here:
Methods in ES6 objects: using arrow functions
(6 answers)
Closed last year.
Can someone please explain why defining a prototype function with lambda expression doesn't work? I thought this must be asked before but couldn't find it.
function Book(title, year) {
this.title = title;
this.year = year;
// define a function within the object, which works fine
this.printYear = () => console.log("instance function of an object: " + this.year);
}
this doesn't work
Book.prototype.printTitle2 = () => {
console.log(this.title);
}
and this is fine of course:
Book.prototype.printTitle = function() {
console.log(this);
console.log(this.title);
}

One of the chief features of arrow functions is that they close over the this from the context in which they're created; they don't get it based on how they're called like other functions do. So...
// ...whatever `this` is *here*
Book.prototype.printTitle2 = () => {
// ...is what `this` will be *here*
console.log(this.title);
};
But your function relies on this varying depending on how it's called.
This just isn't a use-case for arrow functions. Use a normal function:
Book.prototype.printTitle2 = function() {
console.log(this.title);
};
Or better yet, use the new class syntax:
class Book {
constructor(title, year) {
this.title = title;
this.year = year;
}
printTitle2() {
console.log(this.title);
}
}

The Arrow function would resolve the context this belongs to the scope where the function was defined. I believe you have defined that function in window scope. So the this will point to window in your function.
You can use normal anonymous function here. And we have to be careful while using arrow functions.

In addition to #t-j-crowder's answer, I wanted to leave a test case (mocha assert) which you can use to visualize which is not working.
Also you can read more about the scope of arrow functions here:
You Don't Know JS
by Kyle Simpson, who explains this in detail.
Basically, an arrow function's this points to the surrounding context of the current context, which comes in handy if you have enclosing functions.
What it does is basically doing the var self = this; thing.
Or as Kyle says:
[...]
Lexical this in the arrow function callback in the previous snippet now points to the same value as in the enclosing makeRequest(..) function. In other words, => is a syntactic stand-in for var self = this.
In cases where var self = this (or, alternatively, a function .bind(this) call) would normally be helpful, => arrow functions are a nicer alternative operating on the same principle. [...]
You can test it yourself with my gist:
https://gist.github.com/jay-bricksoft/96738dd8a48ceb9f517e914b834cc1ee
In my test case this was the output:
Lambda
function(){}
√ should equal function´s type
1) should have equal context as function
2) should be able to be used as constructor
1 passing (39ms)
2 failing
1) Lambda function(){} should have equal context as function:
AssertionError: 'undefined' == 'string'
+ expected - actual
-undefined
+string
at Context.<anonymous> (test\index.js:29:14)
2) Lambda function(){} should be able to be used as constructor:
TypeError: construct_l is not a constructor
at Context.<anonymous> (test\index.js:34:20)
EDIT: added example / reference to Kyle Simpson's "You Don't Know ES6"
https://github.com/getify/You-Dont-Know-JS/tree/master/es6%20%26%20beyond

Related

Why doesn't JS always bind `this` to `foo` when foo.fn() is called?

I think JavaScript ES6's arrow functions have two changes:
get rid of the "lost binding issue".
make this not bind to foo when foo.fn() is called.
For (1) above, the following code can illustrate (running inside of Node console):
var peter = {
name: "Peter Pan",
greetLater: function() {
setTimeout(function() {
console.log("Hi my name is", this.name);
}, 0);
}
};
peter.greetLater(); // => Hi my name is undefined
var michael = {
name: "Michael J Fox",
greetLater: function() {
setTimeout(() => {
console.log("Hi my name is", this.name);
}, 0);
}
};
michael.greetLater(); // => Hi my name is Michael J Fox
For (2) above, the following code can illustrate:
var winona = {
name: "Winona Ryder",
greet: function() {
console.log("Hi my name is", this.name);
}
};
winona.greet(); // => Hi my name is Winona Ryder
var demi = {
name: "Demi Moore",
greet: () => {
console.log("Hi my name is", this.name);
}
};
demi.greet(); // => Hi my name is undefined
I can understand (1) is a good thing as it solves the "lost binding" issue. But (2) is like "cutting the binding". It might seem that (2) is to solve the issue of (1), which is to go up the lexical scope to find this, but I think having (1) and not having (2) can co-exist: that is, when foo.fn() is called, the this inside the code of fn() can still refer to foo.
What is wrong with when foo.fn() is called, the this inside the code of fn() can still refer to foo, and when it is "dangling function", as in the SetTimeout() in (1) above, or in the following code:
winonaGreet = winona.greet;
winonaGreet(); // => Hi my name is undefined
then it uses the new behavior of going up the lexical scope to find the this? Isn't this more coherent with everything?
That is, when it is fn() or passed to SetTimeout and stored as fn and later invoked as fn(), then look up the lexical scope, but for foo.fn(), it just make a lot of sense to bind this to foo instead of looking up the lexical scope.
Why would we have 2 new rules, one to keep the binding and one to cut it?
And it seems for (2), the ways we can still call foo.fn() and have this inside of fn() bind to foo is to not use arrow function, or use ES6's class, as in Mozilla's example:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
// Getter
get area() {
return this.calcArea();
}
// Method
calcArea() {
return this.height * this.width;
}
}
but then, when we have (1), why do we have (2) also? It is like a hybrid of most other languages, where if foo.fn() is called, the this is always bound to foo.
this and Arrow Functions:
Arrow functions, introduced in ES6, provides a concise way to write functions in >JavaScript.
Another significant advantage it offers is the fact that it does not bind its own this. In other words, the context inside arrow functions is lexically or statically defined.
What do we mean by that?
Unlike other functions, the value of this inside arrow functions is not dependent on how they are invoked or how they are defined.It depends only on its enclosing context.
Thus, regardless of whether the arrow function was called using function invocation or method invocation, it retains the value of this from its enclosing context.In other words, an arrow function’s this value is the same as it was immediately outside it.
If used outside any enclosing function, an arrow function inherits the global context, thereby setting the value of this to the global object.
In classic function expressions, the this keyword is bound to different values based on the context in which it is called.
There are a few subtle differences in behavior between ordinary function functions and arrow functions. Arrow functions do not have their own this value. The value of this inside an arrow function is always inherited from the enclosing scope.
Arrow Functions lexically bind their context so this actually refers to the originating context.
There are a few other differences: arrow functions don’t get their own arguments, super, or new.target keywords. Arrow functions are anonymous, which means that they are not named, so if your function needs to have a self-reference at any point (e.g. recursion, event handler that needs to unbind), it will not work.
More info https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/
A scope in JS is associated to a function. When you create an object using new, this is created in constructor.
const foo = new Foo();
foo.fn()
In above code, context is created in constructor and fn derives its context from foo.
How does this work?
A function has an internal property [[prototype]], which stores context. By default it is not set (or set to default global scope) and it derives/ overrides context via caller. So in foo.fn(), context refers to foo. But if you do var fn = foo.fn; fn(), here context is of global/default scope.
To avoid this, we use Arrow function. Arrow function does not have an internal context and uses the context it is defined in. So above code var fn = foo.fn; fn(); will work.
However, if you define Arrow function inside an object literal, it will still point to the parent scope it was defined in and will not fallback to object.
Sample:
function Foo1() {
this.fn = function () {
console.log(this.constructor.name, this);
}
}
var foo2 = {
fn: function() {
console.log(this.constructor.name, this);
}
}
function test() {
var foo3 = {
fn: function() {
console.log(this.constructor.name, this);
}
}
foo3.fn();
}
function test2() {
var foo3 = {
fn: () => {
console.log(this.constructor.name, this);
}
}
foo3.fn();
}
var foo1 = new Foo1();
foo1.fn();
foo2.fn();
test();
test2();

Am I misunderstanding the use of `this` in React or even in Javascript?

There are already several questions on this topic, and I've looked at all I've found - my question is in order to clear up for myself some (apparent) contradictions that I'm seeing. I suspect there is a better solution than the only one I have working right now. I'm pretty new to Javascript.
I've read through the scoping rules on this as described by e.g. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this . My understanding from reading is that although a lot depends on calling context, if a function is a method of an object then within the function this will be the object itself. I thought this rule trumped the other rules, but perhaps I have misunderstood.
I've also read a post at https://medium.com/byte-sized-react/what-is-this-in-react-25c62c31480 which essentially says that if I want to access object state in a method via this, and I have code like
class App extends Component {
constructor(props) {
super(props);
}
clickFunction() {
console.log(this.props.value);
}
render() {
return(
<div onClick={this.clickFunction}>Click Me!</div>
);
}
}
then I need to explicitly bind the object to clickFunction() by either adding a line to the constructor like
this.clickFunction = this.clickFunction.bind(this);
or by using arrow notation to define clickFunction(), like
const clickFunction = () => { ... }
The first of these solutions works for me - I have not got the second working. It seems strange to me that I need to use either solution since (a) it seems to contradict what I thought was the assertion in the docs that an object method will treat the object as this, and (b) I don't see people doing this sort of thing in other tutorial examples that I look at.
For instance, there is a React tutorial at https://reactjs.org/tutorial/tutorial.html which defines object methods like renderSquare(i) and does not at any point explicitly bind these methods to the object.
If I try to do something which seems to me completely analogous to that tutorial, and don't explicitly add lines to the constructor to bind each method to the object, i.e. lines like this.clickFunction = this.clickFunction.bind(this), then I can't get my code to work.
Can anyone explain to me what I am misunderstanding about the tutorial and the documentation - why does the tutorial work even though there is no explicit binding to the object? The only difference I can spot between it and my own code is that I have use strict. Is there a better fix than the this.clickFunction.bind(this) solution I'm currently using? Adding one extra line of code to the constructor per method, to explicitly bind all my methods, seems pretty clunky.
Arrow functions binds your functions to your class directly. But when if you use
const clickFunction = () => { ... }
This will create a inner function, and does not bind it to the class.
You can use
clickFunction = () => { ... }
which will do similar to
this.clickFunction = this.clickFunction.bind(this);
You're right that, when calling a function from an object, the this keyword ends up being that object. So running something like:
const app = new App();
app.clickFunction();
Would yield the result you're expecting, because it's being called directly from the App class.
However, when you use that function as an event handler in your JSX, you're passing a reference to that function as a callback. By default, the function's this keyword is not determined until you call it, so it will be assigned based on the lexical context it's called from. You could imagine, when you set the handler, something like the following is happening under the hood:
const callback = app.clickFunction;
// click event happens
callback(event);
Here you can see that the call to callback() is just a bare function call. There's no app. prefixing it to provide the lexical context for this.
The two ways around this behavior, which you've already listed, explicitly set the this keyword to the object they originally live on. Calling this.clickFunction = this.clickFunction.bind(this) is the most explicit in that it takes a normal function and manually binds this to the value of this during object construction. Which will be the object being constructed.
Arrow functions do the same thing, but without the explicit binding. This is actually a functional difference between arrow functions and regular functions that a lot of people gloss over since they're typically chosen for stylistic or brevity purposes. Arguably, arrow functions behave as most programmers would expect, while normal functions behave in a way that's pretty unique to Javascript (and therefore pretty confusing).
Second arrow method, it will take this reference where the method is defined not from where it is called. so it will take this reference of class.
Ref. this in arrow function
You have valid points
Why tutorial worked? If you see renderSquare implementation you will notice that it is not using this in its implementation so it does not have to bind itself with this. Your implementation might not working because you may be using this inside method implementation.
renderSquare(i) {
return <Square value={i} />;
}
When you get references like this.clickFunction, you are only getting reference of that particular function which is not bind to any object, which is why calling it will fail if you try to refer variables using this
See this fiddle https://jsfiddle.net/yh3jw5nk/1/ for more explaination
This is determined at runtime and depending on the code, it can be something different.
this is
determined at runtime, when a function is envoked
determined by how a function is invoked, not where the function is
defined
a reference to an object.
will always be an object
global (this) not available in strict mode
Example 1: this = window
var name = 'Global';
var callName1 = function() {
var name = 'Peter';
console.log('--- From callName1 ----');
console.log(this.name);
//console.log(this);
callName2();
}
var callName2 = function() {
var name = 'Jane';
console.log('--- From callName2 ----');
console.log(this.name);
//console.log(this);
}
callName1();
var execute = function(fn) {
var name = 'Mary';
console.log('--- From execute ----');
console.log(this.name);
//console.log(this);
}
execute(callName2);
Example 2: not available in strict mode
'use strict';
var name = 'Global';
var callName1 = function() {
var name = 'Peter';
console.log('--- From callName1 ----');
console.log(this.name);
console.log(this);
}
callName1();
Example 3: examining this with method invocation
var name = 'global';
var obj = {
name: 'James Obj1',
func: function() {
console.log('--- From func ----');
console.log(this.name);
console.log(this); // this reference obj1
}
}
obj.func()
var obj2 = {
name: 'Jame Obj2',
func: obj.func // this reference obj2, but the function is defined in obj1
}
obj2.func()
var obj3 = {
name: 'Kane Obj3',
obj4: {
name: 'Mary Obj4',
func: function () {
console.log('--- From obj4 ----');
console.log(this.name);
console.log(this); // this reference obj4
}
}
}
obj3.obj4.func()
With () => {} function this - is lexically bound. It means that it uses this from the code that contains the arrow function.

Object method functions: Anonymous or named? [duplicate]

This question already has answers here:
When should I use arrow functions in ECMAScript 6?
(9 answers)
Closed 6 years ago.
I've been seeing both types of code and I'm wondering if there is a preference; Using anonymous or named functions:
function myFunc() {
this.myMethod = () => {
//..
}
}
function myFunc() {
this.myMethod = function() {
//..
}
}
Taken from MDN:
An arrow function expression has a shorter syntax compared to function
expressions and does not bind its own this, arguments, super, or
new.target. Arrow functions are always anonymous. These function
expressions are best suited for non-method functions and they can not
be used as constructors.
It makes sense to us anonymous as you might want to access myFunc properties without having to do _this = this. On the other hand it states anonymous functions are best suited for non-method functions (i.e. callbacks).
Those are not contradictory.
It makes sense to use anonymous arrow functions as you might want to access myFunc instance properties without having to do _this = this.
Yes. Though if it was a method, you could simply use this within the function expression and it would work.
On the other hand it states anonymous functions function expressions are best suited for non-method functions (i.e. callbacks).
The "non-method" refers to functions that are not (always) invoked using the object.method(…) pattern that does set the this keyword. It does not matter whether the function is stored as an object property or not.
Btw, none of these points have anything to do with named vs anonymous expressions.
Technically - it doesn't matter.
var myFunction = function() { } //anonymous
and
var myFunction = function myFunction() { } //named
Will be identical in all regards but one - using debug tools and looking at stack traces will show different identifiers. The first version will show up as (anonymous function) while the latter will show up with its name - myFunction. So, named functions are purely for developer convenience and for development.
Worth noting that the name of the function does not need to be the same as the reference to it, for example you can have
var myFunction = function someOtherName() { /* ... */ }
and then this will show up as someOtherName in dev tools. However you will not be able to call it by doing someOtherName() - the name and the reference to the function are different things. For simplicity they are usually set to the same identifier.
Now, onto your example - there is a difference to what you posted
function myFunc() {
this.myMethod = () => {
//..
}
}
This is not equivalent to a named function. This is using the ES6 arrow functions - normally, they will be named the same as the variable they are assigned to:
var arrowFunction = () => {};
var obj = {
arrowMethod: () => {}
}
console.log("function name is: " + arrowFunction.name);
console.log("object property function name is: "+ obj.arrowMethod.name);
(note that this works in Chrome but not in Firefox for some reason - the .name property is supposed to be set)
Further to the naming differences, arrow functions have other differences to a "plain" function. Most notably, their context is lexically bound. Here is what this means in practice
function arrowExample() {
this.data = "Hello arrow";
this.myMethod = () => {
return this.data;
}
}
function normalFunctionExample() {
this.data = "Hello normal function";
this.myMethod = function myMethod() {
return this.data;
}
}
var arrowInstance = new arrowExample();
var normalFunctionExampleInstance = new normalFunctionExample();
console.log("Invoking arrow with context: " + arrowInstance.myMethod());
console.log("Invoking normal function with context: " + normalFunctionExampleInstance.myMethod());
var arrowReference = arrowInstance.myMethod;
var normalFunctionReference = normalFunctionExampleInstance.myMethod;
console.log("Invoking arrow without context: " + arrowReference());
console.log("Invoking normal function without context: " + normalFunctionReference());

What are ES6 arrow functions, how do they work? [duplicate]

This question already has answers here:
Are 'Arrow Functions' and 'Functions' equivalent / interchangeable?
(4 answers)
Closed 6 years ago.
I am curious about ES6 arrow functions (fat arrow functions). Are they simply syntactic sugar derived from CoffeeScript, or is there more to them than meets the eye?
ES6 Arrow functions in depth
One of the prettiest features of ES6, it could easily win a beauty contest, if such a contest would be held. What many people don’t know is that the arrow function is not simply a form of syntactic sugar that we can use instead of the regular callback.
As I like to explain it to the people who attend my trainings/workshops, arrow functions are this-less, arguments-less, new.target-less and super-less.
Let us now get past the shorter syntax and dive deeper into the specifics of the arrow function.
Lexical-bound this
Previously, regular functions would have their this value set to the global object if they were used as callbacks, to a new object in case they were called with the new operator or, in the case of libraries like jQuery, they would be set to the object that triggered an event in case of event handlers, or the current element in a $.each iteration.This situation proved very confusing even for experienced developers.
Let’s say you have a piece of code like the one below.
var obj = {
nameValue: 'default',
initializeHandlers: function() {
var nameInput = document.querySelector('#name');
nameInput.addEventListener('blur', function(event) {
this.nameValue = event.target.value;
});
}
};
obj.initializeHandlers();
The problem is that this inside the blur event handler is set to the global object rather than obj. In strict mode — ‘use strict’; — you risk breaking your application because this is set to undefined. In order to side-step this issue we have two options:
Convert the event handler to a function bound to the outer scope, using Function.prototype.bind
Use the dirty var self = this; expression in the initializeHandlers function (I see this as a hack)
Both options are illustrated below.
[...]
initializeHandlers: function() {
var nameInput = document.querySelector('#name');
// more elegant but we can do better
var blurHandler = function(event) {
this.nameValue = event.target.value;
}.bind(this)
nameInput.addEventListener('blur', blurHandler);
}
[...]
[...]
initializeHandlers: function() {
var nameInput = document.querySelector('#name');
// ugly and error-prone
var self = this;
nameInput.addEventListener('blur', function(event) {
self.nameValue = event.target.value;
});
}
[...]
On the other hand, arrow functions have no internal context. They inherit their context from the outer scope. Let’s take a look at how arrow functions solve this problem.
const obj = {
nameValue: 'default',
initializeHandlers: function() {
const nameInput = document.querySelector('#name');
nameInput.addEventListener('blur', (event) => {
// this references obj instead of the global object
this.nameValue = event.target.value;
});
}
};
In our new implementation this is a hard reference to the obj object and doesn’t get lost due to nesting.
Lexical arguments
Have you ever tried to access the arguments object inside an arrow function? I have, and I wasted 3 solid hours trying to figure out why do I get the arguments of the outer function instead of those of the arrow functions.
Thankfully, MDN exists, and as good practice dictates, you check the documentation at the end, when you sit in a corner, knees tucked to your chest, rocking and repeating to yourself: “I should have been a carpenter!”
Fun aside, arrow functions do not expose an arguments object. If you try to access it, you will get the arguments of the surrounding function. In our case, given the fact that the outer function is an arrow function as well, and we have no more functions further up the chain, we will get a ReferenceError.
const variadicAdder = (x) => {
return () => {
let args = Array.prototype.slice.call(arguments, 0);
return args.reduce((accumulator, current) => {
return accumulator + current;
}, x);
}
}
const variadicAdderOf5 = variadicAdder(5);
console.log(variadicAdderOf5(10, 11, 12));
// ReferenceError: arguments is not defined
There is no fix here, as there is nothing broken. What we can do is to return a plain function, rather than an arrow, from our variadicAdder().
This will give us the opportunity to access the arguments object without an issue. The updated code will look like the one below with the only difference
that it will actually work and not throw an error.
const variadicAdder = (x) => {
return function() {
let args = Array.prototype.slice.call(arguments, 0);
return args.reduce((accumulator, current) => {
return accumulator + current;
}, x);
}
}
const variadicAdderOf5 = variadicAdder(5);
console.log(variadicAdderOf5(10, 11, 12));
// 38
To find out more about Array.prototype.reduce, head to the Mozilla Developer Network.
Other characteristics
As I mentioned in the introductory section of this article, arrow functions have several more characteristics besides the context and the arguments.
The first thing I would like to mention is that you are unable to use the new operator with arrow functions. As a direct implication, arrow functions also don’t have super(). Snippets like the one below would simply throw a TypeError.
const Person = (name) => {
this.name = name;
};
let p = new Person('John');
// TypeError: Person is not a constructor
The third characteristic, which is as well, a direct implication of the inability to use the new operator, is the fact that arrow functions don’t have new.target. In a nutshell, new.target allows you to detect whether or not a function has been called as a constructor.
Arrow functions, inherit new.target from their surrounding scope. If the outer scope is a function, and it is called like a constructor (e.g. new Person('Adrian');), then new.target will point to the outer function.
The Mozilla Developer Network hosts a detailed explanation on new.target and I encourage you to check it out.
This article is also published on my blog, here: /es6-arrow-functions-in-depth/

Why cannot use lambda to define prototype function [duplicate]

This question already has answers here:
Methods in ES6 objects: using arrow functions
(6 answers)
Closed last year.
Can someone please explain why defining a prototype function with lambda expression doesn't work? I thought this must be asked before but couldn't find it.
function Book(title, year) {
this.title = title;
this.year = year;
// define a function within the object, which works fine
this.printYear = () => console.log("instance function of an object: " + this.year);
}
this doesn't work
Book.prototype.printTitle2 = () => {
console.log(this.title);
}
and this is fine of course:
Book.prototype.printTitle = function() {
console.log(this);
console.log(this.title);
}
One of the chief features of arrow functions is that they close over the this from the context in which they're created; they don't get it based on how they're called like other functions do. So...
// ...whatever `this` is *here*
Book.prototype.printTitle2 = () => {
// ...is what `this` will be *here*
console.log(this.title);
};
But your function relies on this varying depending on how it's called.
This just isn't a use-case for arrow functions. Use a normal function:
Book.prototype.printTitle2 = function() {
console.log(this.title);
};
Or better yet, use the new class syntax:
class Book {
constructor(title, year) {
this.title = title;
this.year = year;
}
printTitle2() {
console.log(this.title);
}
}
The Arrow function would resolve the context this belongs to the scope where the function was defined. I believe you have defined that function in window scope. So the this will point to window in your function.
You can use normal anonymous function here. And we have to be careful while using arrow functions.
In addition to #t-j-crowder's answer, I wanted to leave a test case (mocha assert) which you can use to visualize which is not working.
Also you can read more about the scope of arrow functions here:
You Don't Know JS
by Kyle Simpson, who explains this in detail.
Basically, an arrow function's this points to the surrounding context of the current context, which comes in handy if you have enclosing functions.
What it does is basically doing the var self = this; thing.
Or as Kyle says:
[...]
Lexical this in the arrow function callback in the previous snippet now points to the same value as in the enclosing makeRequest(..) function. In other words, => is a syntactic stand-in for var self = this.
In cases where var self = this (or, alternatively, a function .bind(this) call) would normally be helpful, => arrow functions are a nicer alternative operating on the same principle. [...]
You can test it yourself with my gist:
https://gist.github.com/jay-bricksoft/96738dd8a48ceb9f517e914b834cc1ee
In my test case this was the output:
Lambda
function(){}
√ should equal function´s type
1) should have equal context as function
2) should be able to be used as constructor
1 passing (39ms)
2 failing
1) Lambda function(){} should have equal context as function:
AssertionError: 'undefined' == 'string'
+ expected - actual
-undefined
+string
at Context.<anonymous> (test\index.js:29:14)
2) Lambda function(){} should be able to be used as constructor:
TypeError: construct_l is not a constructor
at Context.<anonymous> (test\index.js:34:20)
EDIT: added example / reference to Kyle Simpson's "You Don't Know ES6"
https://github.com/getify/You-Dont-Know-JS/tree/master/es6%20%26%20beyond

Categories

Resources