Aliases give a name to a command's yielded value, a route (cy.intercept), or an element, so you can reference it later with the @ syntax without re-querying or storing variables.
cy.get('[data-cy=table]').as('table') lets you later do cy.get('@table').find('tr'). For network stubs, cy.intercept(...).as('save') then cy.wait('@save') synchronizes on the request and exposes its details for assertions (cy.get('@save').its('request.body')). Aliases respect Cypress's async model and retry-ability better than plain variables, and they are reset between tests. Use aliases to share elements, requests, and fixture data across steps cleanly. For DOM aliases, Cypress re-queries when possible to avoid stale references.
cy.intercept('POST', '/api/orders').as('createOrder'); ... submit form ...; cy.wait('@createOrder').its('response.statusCode').should('eq', 201); asserts the order API returned 201 after the UI action.
Why is cy.get('[data-cy=row]').as('rows') preferable to const rows = cy.get('[data-cy=row]')?