Javascript Arrow Functions

Dive deep into the world of Javascript Arrow Functions with this comprehensive guide. Delve into the fundamental concepts, understand when to use them, and rectify common misconceptions. Examine the differences and similarities between Arrow Functions and classic functions. Unravel the syntax of Arrow Functions and explore their use in asynchronous programming. Finally, understand the practical applications in array mapping, within Classes and Nesting; ensuring you exploit their benefits in a real-life context. A thorough understanding of Javascript Arrow Functions will undoubtedly elevate your programming skills to the next level.

Javascript Arrow Functions Javascript Arrow Functions

Create learning materials about Javascript Arrow Functions with our free learning app!

  • Instand access to millions of learning materials
  • Flashcards, notes, mock-exams and more
  • Everything you need to ace your exams
Create a free account
Table of contents

    Understanding Javascript Arrow Functions

    Javascript Arrow Functions not only represent a new way of writing functions within JavaScript, but also introduce a whole lot of different functionality that was previously troublesome to deal with in JavaScript. These functions, also widely known as 'Fat Arrow' Functions, provide a new way to declare and utilise function expressions.

    The Fundamental Concept of Javascript Arrow Functions

    Arrow Functions (=>) was introduced in ES6 to create function expressions in a more condensed format. It is a shorter syntax for writing function expressions. Arrow functions do not create their own 'this' value, they inherit the one from the context in which they were defined, aiding in handling common, but troublesome, JavaScript pitfalls.

    Here is a comparative example showing how concise Javascript Arrow Functions are exactly:

    Traditional Function Expression:

    function(a) {
      return a + 100;
    Arrow Function Expression:
    a => a + 100;
    These two pieces of code have the same functionality.

    Unlike traditional function expressions, arrow functions cannot be used as constructors. That is, you cannot use new with an arrow function. Attempting to do so will throw an error.

    When to Use Javascript Arrow Functions

    Arrow Functions offer concise syntax and a proper lexical 'this' value, making them beneficial in a variety of use cases:
    • Single line callbacks: Arrow functions are perfect for single line callback functions that only include a return statement. With their shorter syntax, your JavaScript code becomes more readable and compact.
    • Lexical 'this': If you always need to bind 'this', using the Arrow Function is a good choice because the function does not generate its own 'this' context.
    On the other hand, when representing methods that can be overridden in subclasses, or in cases where maintaining the function's own identity is important, classical function expressions are preferred.

    Common Misconceptions about Javascript Arrow Functions

    There's a common misconception that arrow functions are just a shorter way to write function expressions. Not true. In fact, they behave quite differently from traditional function expressions:
    PropertiesArrow FunctionFunction Expression
    thisInherited from enclosing contextDepends on how the function is called
    argumentsNot availableYes, it's available
    newCannot be calledYes, it can be called
    Using JavaScript Arrow Functions efficiently means understanding these differences. But once you get the hang of it, they can be a powerful tool in your JavaScript toolkit.

    Javascript Arrow Function vs Function: A Comparative Analysis

    Javascript, being a dynamic language, offers various ways to define and call functions. Two major ways of defining functions that are widely used are the classic or traditional functions and the newer, more concise arrow functions. Both have their own merits, and their usage depends on the specific use cases, which we will discuss in detail.

    Similarities Between Javascript Arrow Functions and Classic Functions

    While arrow functions and classic functions may have their differences, they share many fundamental aspects as well. Both of them are capable of executing blocks of code. You can pass parameters to both, albeit the syntax differs slightly. Regardless of their form factor, they often share the same end result of processing inputs to return outputs. Consider the following examples of a classic function and an arrow function, both performing exactly the same operation: Classic function:
    function add(a, b) {
      return a + b;
    Arrow function:
    let add = (a, b) => a + b;
    While their syntax and a few other characteristics vary, both types of functions can be used to successfully compute the desired results.

    Differences in Syntax: Javascript Arrow Function vs Function

    Even though they may obtain the same result, as can be seen from the previous example, Javascript Arrow Function and Classic Function have prominent differences in their syntax. - The most visible difference is that arrow functions are much more concise than traditional function expressions. For instance: Table showing traditional function vs arrow function syntax:
    Syntax TypeTraditional FunctionArrow Function
    KeywordUses 'function'No 'function' keyword
    Syntax LengthRelatively longerShort and concise
    Return StatementExplicit for multi-line functionsImplicit for single-line functions

    Use Case Scenarios: Javascript Arrow Function and Regular Function

    Use of arrow functions versus traditional functions is largely determined by the specific requirement of the JavaScript code. Arrow functions are most useful when writing small, anonymous functions, such as those passed to high-order functions. The benefits of using arrow functions stem from their concise syntax and resolution of the 'this' keyword. However, traditional functions continue to be crucial in multiple cases. For instance,
    • When writing functions that will be used as constructors to create new objects with the new keyword, traditional functions are necessary because arrow functions do not support new.
    • If your function needs to include a method called super, which allows you to use methods of the parent class in the child class, you cannot use arrow functions because they do not have a prototype and hence cannot call super.
    • Traditional functions also allow overloading based on the number of arguments, thanks to the arguments keyword, which is not available in arrow functions.
    In conclusion, the choice between arrow and traditional functions should consider the benefits and drawbacks of each function type and the specific requirements of the code.

    Exploring the Syntax of Javascript Arrow Functions

    Understanding the syntax of Javascript Arrow Functions is fundamental to effectively using this feature. As with any programming language, syntax governs how you construct your scripts and functions, therefore, getting the syntax right ensures your code will be successfully parsed and executed.

    Importance of Correct Javascript Arrow Function Syntax

    When it comes to Javascript Arrow Functions, learning and implementing the correct syntax is vital. Arrow functions were introduced to address some of the quirks in the original design of JavaScript function declarations and to provide a more concise, and readable way to write function expressions. As such, they have their own unique syntax, which can be a powerful tool, but it also requires deeper understanding to avoid common pitfalls and errors. One of the key features of arrow functions that separates them from traditional function declarations is their handling of the "this" scope. For instance, in traditional JavaScript function syntax, the "this" keyword is bound depending upon how the function is called. In arrow functions, however, "this" gets lexically bound; implying it preserves the "this" value of the outer function.

    Lexical Scoping in JavaScript means that a child scope always has access to the variables and parameters of its parent scope, even if the parent function has finished its execution. Lexical scope is used in arrow functions.

    Arrow functions also feature a more concise syntax, which can make your code cleaner and easier to read. However, this compact syntax comes with its own nuances and complexities, meaning a thorough understanding is required to make the most of them.

    Common Syntax Errors in Javascript Arrow Functions

    There are several common mistakes made when writing arrow functions that stem from misunderstandings or overlooking the syntactical nuances. By correcting these, you can significantly improve your usage of arrow functions. - Incorrect Syntax: While the basic syntax of arrow functions is relatively straightforward, when it comes to exceptions the details can be misleading. For instance, a common error involves forgetting to wrap function parameters in parentheses when there is more than one parameter.
    const foo = a, b => a + b; // incorrect
    const foo = (a, b) => a + b; // correct
    - Misunderstanding Lexical 'this': As the keyword 'this' in arrow functions is lexically bound to the context of the outer function, it can often lead to confusion if you're accustomed to regular functions. Test, understand and apply this concept before implementing. - Omitting the 'return' Statement: In multi-line arrow functions, forgetting the 'return' statement is a common mistake. While in single-line arrow functions you have an implicit 'return', in multi-line arrow functions, an explicit 'return' is required.
    let add = (a, b) => { // multi-line arrow function
      let sum = a + b;
    } // incorrect as there is no return statement
    let add = (a, b) => { // multi-line arrow function
      let sum = a + b;
      return sum; // correct
    Understanding and rectifying these common syntax errors could be a significant step to enhance your proficiency in using JavaScript arrow functions.

    Syntax Examples: Unravelling Javascript Arrow Function Syntax

    To get a complete understanding of Javascript Arrow Functions, let's go through different syntax examples. - Single Parameter: If your arrow function has a single parameter, you can choose to omit parentheses.
    let square=x => x*x;
    - Multiple Parameters: For functions with multiple parameters, parentheses are required.
    let add = (a, b) => a + b;
    - No Parameters: If there are no parameters, you will still need to include an empty set of parentheses.
    let greet = () => console.log('Hello World');
    - Implicit Return: For single-line functions, where you have a single statement, you can exclude the curly brackets and the return statement. In this case, the value of the statement is returned implicitly.
    let double = (x) => 2 * x;
    - Explicit Return: For multi-line functions or when there are multiple lines of code within the function, you must use curly brackets and an explicit return statement.
    let add = (a, b) => {
      console.log('Addition function called!');
      return a + b;
    Breaking down these various cases can help demystify the syntax of JavaScript arrow functions, and aid in effectively employing them in your code. Understanding the correct syntax and being aware of common syntax errors will be crucial for writing effective and error-free JavaScript.

    Delving into Async Arrow Function in Javascript

    Async arrow functions are a subset of arrow functions used specifically with asynchronous programming in Javascript. These asynchronous tasks could be handling requests to a server, loading assets like images and scripts, or anything that could potentially take more than a few milliseconds to complete. In Javascript, these "longer than a moment" tasks can be handled asynchronously, freeing up your main thread to continue executing other code.

    Breaking down Async Arrow Function in Javascript

    Async arrow functions are a way to write asynchronous code in Javascript that is much more concise than using traditional Promise syntax or even async/await with traditional function syntax.

    An Async function is a function declared with the async keyword, and the await keyword is permitted within them. Async functions are used to work with promises in a more comfortable syntax.

    An async arrow function declaration would look something like this:
    let myAsyncFunction = async () => {
      // asynchronous code here
    In more detail, the async keyword before a function has two effects:
    • It ensures that the function always returns a promise: If a function that is marked as async does not return a value, or if it returns a non-promise value, JavaScript automatically wraps that value in a resolved promise.
    • It allows the await keyword to be used in the function: The await operator is used to pause and resume a JavaScript async function and to wait for a promise's resolution or rejection.

    Role of Async Arrow Functions in Javascript Programming

    The introduction of async arrow functions in Javascript has significantly improved the way programmers can write and manage asynchronous code. Async arrow functions offer a more streamlined syntax for working with asynchronous code, simplifying catching errors with ".catch()", and function chaining with ".then()". This makes it markedly easier to read and trace asynchronous code, making debugging a far easier task. Moreover, async arrow functions don't bind their own "this" value. This makes them ideal for use-cases where you want to preserve the context of this from its originating scope. It's particularly useful when working with object-oriented programming in JavaScript, such as calling asynchronous methods on a class object.

    Common Applications of Async Arrow Function in Javascript

    Async arrow functions are extensively used in Javascript, primarily when performing tasks that require significant time to complete and can afford to be done later, thereby keeping the webpage responsive. Some common applications include: - Fetching data from servers: AJAX, and more recently, fetch() API functions are often asynchronous, returning a promise that gets resolved when the data arrives from the server.
    let fetchData = async() => {
      let response = await fetch('');
      let data = await response.json();
      return data;
    - React and other JavaScript libraries/frameworks: Libraries like React use async functions for lifecycle methods to integrate asynchronous actions gracefully into the framework's flow. - Delays: Asynchronous functions can deliberately halt the progress of a function using promises that resolve after a set time, creating a delay.
    let delay = async() => {
      await new Promise(resolve => setTimeout(resolve, 5000));
      console.log('This message is displayed after a 5 seconds delay.');
    - Any time you need to wait for a promise to resolve: Whenever a Promise is involved, that's a chance to use an async function.
    let example = async () => {
        let promise = new Promise((resolve, reject) => {
            setTimeout(() => resolve("Promise resolved!"), 2000)
        let result = await promise; 
        console.log(result); // "Promise resolved!"
    However, it's essential to be careful in deciding where to use asynchronous functions, as managing too many promises and async operations can also lead to complex code and potential performance issues.

    Array map and Javascript Arrow Functions

    Integrating javascript arrow functions with array methods can result in slick, efficient code. The map() array method is one such typical example that often gets used with arrow functions, offering a concise way to manipulate and transform arrays.

    Understanding Array Map with Javascript Arrow Function

    The map() method creates a new array populated with the results of calling a provided function on every element in the calling array. Array map is a non-mutating method, meaning it creates a new array and does not modify the original array.

    The Map() function is a inbuilt function in JavaScript which maps the array by calling a function on all elements of an array and returns a new array by the function.

    Arrow Functions in JavaScript are designed to have short syntax and not have its own this, arguments, super, or

    The syntax when using the array map method with an arrow function is as follows:
    let newArray = => {
      // transformation
      return newValue;
    Here's a simple example where array map is used with an arrow function to double every number in an array:
    let numbers = [1, 2, 3, 4, 5];
    let doubled = => number * 2);
    console.log(doubled); // [2, 4, 6, 8, 10]
    By utilizing arrow functions, long functions declarations can be reduced to one line of code, making the code more accessible and readable. The code is also more streamlined as the "function" and "return" keywords are not needed.

    Practical Applications: Array Map with Javascript Arrow Function

    The array map method combined with arrow functions can be used in a plethora of ways to handle and manipulate array data effectively. Here are a few examples drawn from practical applications. - Transforming array data: By applying a transform to each item in the array. For example, doubling each value in an array as mentioned before.
    let values = [1, 2, 3, 4];
    let doubleValues = => value * 2);
    - Extracting a subset of data: Pull out specific key-value from an array of objects.
    let users = [{name: 'Alice', age: 25}, {name: 'Bob', age: 30}];
    let names = =>;
    - Formatting data for output: Extract and format data suitable for display.
    let pets = [{name: 'Fluffy', type: 'Dog'}, {name: 'Felix', type: 'Cat'} ];
    let petDescriptions = => `${} is a very cute ${pet.type}`);
    Using Array map with Javascript Arrow Function really helps fine-tune your codes and makes for efficient programming.

    Manipulating Arrays: Javascript Arrow Function in Practice

    Manipulating arrays is a core part of any programming language and Javascript is no exception. Javascript offers a variety of array methods like map(), filter(), reduce(), which coupled with the arrow function syntax, can make your code clean, readable, and efficient.
    let prices = [100, 200, 300, 400, 500];
    let discounted = => price - price * 0.2);
    In the above example, the map() function is used along with an arrow function to apply a discount to every item in the array. Another practical application can be found when dealing with multiple arrays at once.
    let products = ['Milk', 'Eggs' , 'Bread'];
    let prices = [1.50, 2.50, 0.90];
    let productsWithPrices =, index) => {
      return { name: product, price: prices[index] }
    In the example above, the map() function is used to create a new array, productsWithPrices, combining data from two other arrays. Double reference to arrays are eliminated, making your code more streamlined and efficient. By judiciously using Javascript arrow functions alongside array methods, it's possible to implement complex requirements using very concise and readable code.

    Javascript Arrow Functions in Classes and Nesting

    Arrow functions have changed the landscape of function declarations in JavaScript in many diverse ways. Not only do they offer syntactic sugar coating, making the code cleaner and more readable, but they are also applied within classes and in nested functions scenarios.

    Incorporating Arrow Function in Class Javascript

    A class is a blueprint from which individual objects are created. In Javascript, classes are primarily syntactic sugar over JavaScript's prototype-based inheritance. The class syntax doesn't introduce a new object-oriented inheritance model to JavaScript. Using arrow functions inside class methods can sometimes simplify class logic, especially when dealing with event handlers. One of the most significant benefits comes when working with the this keyword. Arrow functions don't have their own this value. The value of this inside an arrow function is always inherited from the enclosing scope. Here's a simple example of this, let's say we have a class to represent a counter.
    class Counter {
      constructor() {
        this.value = 0;
      increment() {
    If we wanted to call the increment method on counter object in some asynchronous code, we would lose our binding of this. Check this out:
    let myCounter = new Counter();
    setTimeout(myCounter.increment, 1000);
    In the above case, the this inside the increment method would not point to myCounter object, which can cause unintended behaviour. But when we use an arrow function, these worries are alleviated.
    class Counter {
      constructor() {
        this.value = 0;
      increment = () => {
    So now, even when calling the increment method from asynchronous code:
    let myCounter = new Counter();
    setTimeout(myCounter.increment, 1000);
    In this case, the this inside the arrow function will always point to myCounter and the function will work as expected no matter where or when it is called.

    Advantages of Using Arrow Function in Class Javascript

    The key benefits of using arrow functions as class methods are centered on the behaviour of this. Here are some advantages of using arrow functions as class methods in JavaScript:
    • Automatically binding 'this': With arrow functions, this is lexically bound. It means that it uses this from the code that contains the arrow function.
    • Simpler syntax: Arrow functions have a shorter syntax compared to function expressions. This results in less code and potentially less confusion.
    • Non-binding of arguments: Arrow functions do not have their arguments object. Thus, they are a great choice for functions you plan to use as methods inside a class.

    Real-life Scenarios: Nested Arrow Functions in Javascript

    It's not uncommon to see nested arrow functions in JavaScript, especially in functional programming pattern where you return functions that operate on the data. By doing this, you can create more composable, modular code. One real-life usage scenario is when using higher-order functions—functions that return function, like in the case of middleware in an Express.js app:
    app.use((req, res, next) => {
      return (stuff) => {
        // Do something with 'stuff'
    This kind of pattern is entirely valid and can be very powerful for creating pipelines of operations. As your functions stay small and focused on doing one thing, they become a lot easier to reason about, debug and test. Here's another example of nested arrow functions in JavaScript:
    let multiply = x => y => x * y;
    let double = multiply(2);
    let result = double(3); // 6
    In the above, multiply() is a higher-order function that returns a function which can then be used to double numbers. In conclusion, arrow functions inside classes and nested arrow functions in JavaScript can make your code less verbose and easier to read, as well as solve annoying issues that come up with the handling of this. They are a powerful addition to JavaScript and understanding how they work will incredibly benefit you in your JavaScript programming journey.

    Understanding the Benefits and Uses of JavaScript Arrow Functions

    JavaScript's Arrow functions can be a game-changer in the way you write code.

    Broad Advantages of Arrow Function in Javascript

    Arrow functions, introduced in ES6, offer a compact syntax to write functions in JavaScript. Even though the primary motivation for arrow functions is to have a shorter syntax, they have advantages far beyond that. Here are some of the significant benefits that arrow functions bring to JavaScript:
    • Succinct Syntax: Arrow functions can reduce the verbosity of your JavaScript code. The code looks cleaner.
    • Lexical Scoping: Arrow functions use lexical scoping for the special variable 'this'. 'This' always represents the object that defined the arrow function.
    • No Arguments Object: Arrow functions do not have the local variable arguments like regular functions.
    • Implicit Returns: If the function body contains only a single statement, you can omit the 'return' keyword and the braces, making your code even more concise.

    Specific Use-Case Benefits of Arrow Function in JavaScript

    Apart from fundamentally changing the way JavaScript functions are written and offering entirely new ways to work with functions, the arrow function syntax has several use cases where it proves particularly beneficial. Event Handlers: One typical use case scenario is in event handlers. Due to their lexical scoping, arrow functions help you to avoid the confusion that sometimes occurs when using 'this' with traditional functions.
      event => {
        // 'this' here is lexically bound from surrounding scope.
    Higher Order Functions: Higher Order Functions either takes one or more functions as parameters or returns a function. Arrow functions have made it significantly simpler and cleaner to write these higher-order functions in JavaScript.
    let names = ['Alice', 'Bob', 'Charlie'];
    let greetings = => `Hello, ${name}`);
    Callback Functions: Arrow functions are commonly used for short function expressions used as arguments, primarily for callback functions. Consider the following example of array sorting using an arrow function:
    let numbers = [19, 3, 81, 1, 24, 21];
    numbers.sort((a, b) => a - b);

    Exploiting the Benefits of Nested Arrow Functions in Javascript

    The use of nested arrow functions in JavaScript is a power-packed feature that can significantly enhance your functional programming abilities. Nesting is an inevitable reality in JavaScript coding, more so in JavaScript, which heavily relies on callbacks, a type of higher-order functions. With the arrival of arrow functions, nesting can be accomplished elegantly, resulting in more readable code. Here is an example of a nested arrow function:
    let greeting = language => name => `Hello, ${name}. Welcome to learning ${language}`;
    let greetingInSpanish = greeting('Spanish');
    console.log(greetingInSpanish('John')); // Hello, John. Welcome to learning Spanish
    In the example above, the greeting function takes language as a parameter and returns another function that takes name as a parameter. This function finally returns the greeting message. As you can see, this leads to cleaner, more modular code. Nested arrow functions are commonly used in JavaScript for currying. Currying is a technique of evaluating a function with multiple arguments, into a sequence of functions, each with a single argument.
    let add = a => b => a + b;
    let addFive = add(5);
    console.log(addFive(3)); // 8
    Here the function add is a higher-order function that accepts a single argument and returns a new function. The returned function also accepts a single argument. This allows us to create new functions on-the-fly. Understanding the benefits and uses of JavaScript's arrow functions could significantly enhance your overall programming capability.

    Javascript Arrow Functions - Key takeaways

    • Javascript Arrow Functions provide a more concise, readable way to write function expressions with a unique syntax that demands close attention to avoid pitfalls and errors.
    • The 'this' scope in arrow functions gets lexically bound, preserving the 'this' value of the outer function, differing from traditional JavaScript function syntax.
    • Understanding common syntax errors in Javascript Arrow Functions, such as incorrect wrapping of function parameters or omitting the 'return' statement in multi-line functions, is important to proficiently use arrow functions.
    • Async arrow functions, a subset of arrow functions, are used with asynchronous programming in Javascript, handling long-running tasks and providing a more concise syntax compared to traditional Promise syntax.
    • Integrating Javascript Arrow Functions with array methods like map() create concise, efficient code. The map() method creates a new array populated with the results of calling a provided function on every element in the original array.
    • Arrow functions are applicable within classes and in nested functions scenarios, offering syntactic benefits and handling of the 'this' keyword.
    Javascript Arrow Functions Javascript Arrow Functions
    Learn with 14 Javascript Arrow Functions flashcards in the free StudySmarter app

    We have 14,000 flashcards about Dynamic Landscapes.

    Sign up with Email

    Already have an account? Log in

    Frequently Asked Questions about Javascript Arrow Functions
    What are the advantages of using Javascript Arrow Functions over traditional function expressions?
    Arrow functions in Javascript offer shorter, cleaner syntax and do not bind their own 'this', 'arguments', 'super' or ''. These functions are also anonymous making them handy for quick, disposable functions that aren't going to be reused.
    Can Javascript Arrow Functions be used as methods within an object?
    Yes, Javascript arrow functions can be used as methods within an object. However, they behave differently as 'this' in an arrow function doesn't bind to the object, but to the surrounding context, which can lead to unexpected results.
    How can one handle 'this' context in Javascript Arrow Functions?
    In Javascript Arrow Functions, the 'this' context is lexically bound. It means that 'this' takes the value of the surroundings where the arrow function is defined, not where it's invoked. Therefore, there's no need to bind 'this' separately.
    Do Javascript Arrow Functions have any restrictions or limitations compared to regular functions?
    Yes, JavaScript Arrow Functions have limitations. They can't be used as constructors, they don't have their own 'this' value, meaning they inherit it from the enclosing context, and they don't have the 'arguments' local variable. Moreover, arrow functions can't have duplicate named parameters like regular functions can in non-strict mode.
    How can parameters be passed in Javascript Arrow Functions?
    Parameters can be passed to Javascript arrow functions similarly to regular functions, by placing them between the parentheses in the function definition. For example: const example = (param1, param2) => { /* function body */ }. If there's only one parameter, parentheses can be optional.

    Test your knowledge with multiple choice flashcards

    What is a fundamental difference between Javascript Arrow Functions and traditional function expressions?

    When should you use Javascript Arrow Functions?

    What are the key differences in syntax between JavaScript's Arrow Functions and Traditional Functions?

    About StudySmarter

    StudySmarter is a globally recognized educational technology company, offering a holistic learning platform designed for students of all ages and educational levels. Our platform provides learning support for a wide range of subjects, including STEM, Social Sciences, and Languages and also helps students to successfully master various tests and exams worldwide, such as GCSE, A Level, SAT, ACT, Abitur, and more. We offer an extensive library of learning materials, including interactive flashcards, comprehensive textbook solutions, and detailed explanations. The cutting-edge technology and tools we provide help students create their own learning materials. StudySmarter’s content is not only expert-verified but also regularly updated to ensure accuracy and relevance.

    Learn more
    StudySmarter Editorial Team

    Team Javascript Arrow Functions Teachers

    • 23 minutes reading time
    • Checked by StudySmarter Editorial Team
    Save Explanation

    Study anywhere. Anytime.Across all devices.

    Sign-up for free

    Sign up to highlight and take notes. It’s 100% free.

    Join over 22 million students in learning with our StudySmarter App

    The first learning app that truly has everything you need to ace your exams in one place

    • Flashcards & Quizzes
    • AI Study Assistant
    • Study Planner
    • Mock-Exams
    • Smart Note-Taking
    Join over 22 million students in learning with our StudySmarter App