Переменная по ссылке javascript

Ссылки — JS: Массивы

Переменные (и константы) в JavaScript могут хранить два вида данных: примитивные и ссылочные. К примитивным относятся все примитивные типы: числа, строки, булеан и так далее. К ссылочным – объекты. Объекты, в общем смысле, изучаются только в следующем курсе, но массив внутри – это тоже объект:

В чем разница между ссылочными и примитивными типами данных и почему об этом нужно знать?

С точки зрения прикладного программиста, разница проявляется при изменении данных, их передаче и возврате из функций. Мы уже знаем, что массив можно менять, даже если он записан в константу. Здесь как раз и проявляется ссылочная природа. Константа хранит ссылку на массив, а не сам массив, и эта ссылка не меняется. А вот массив поменяться может. С примитивными типами такой трюк не пройдет.

Другой способ убедиться в том, что массивы являются ссылками – создать несколько констант, содержащих один массив, и посмотреть, как они меняются:

const items = [1, 2]; // Ссылаются на один и тот же массив const items2 = items; items2.push(3); console.log(items2); // => [1, 2, 3] console.log(items); // => [1, 2, 3] items2 === items; // true 

Сравнение массивов тоже происходит по ссылке. Это может быть очень неожиданно с непривычки. Одинаковые по структуре массивы имеют разные ссылки и не равны друг другу:

Более того, если передать массив в какую-то функцию, которая его изменяет, то массив тоже изменится. Ведь в функцию передается именно ссылка на массив. Посмотрите на пример:

const f = (coll) => coll.push('wow'); const items = ['one']; f(items); console.log(items); // => [ 'one', 'wow' ] f(items); console.log(items); // => [ 'one', 'wow', 'wow' ] 

Проектирование функций

Проектируя функции, работающие с массивами, есть два пути: менять исходный массив или формировать внутри новый и возвращать его наружу. Какой лучше? В подавляющем большинстве стоит предпочитать второй. Это безопасно. Функции, возвращающие новые значения, удобнее в работе, а поведение программы становится в целом более предсказуемым, так как отсутствуют неконтролируемые изменения данных.

Читайте также:  Html allow cross origin

Изменение массива может повлечь за собой неожиданные эффекты. Представьте себе функцию last() , которая извлекает последний элемент из массива. Она могла бы быть написана так:

// Метод .pop извлекает последний элемент из массива // Он изменяет массив, удаляя оттуда этот элемент const last = (coll) => coll.pop(); 

Где-то в коде, вы просто хотели посмотреть последний элемент. А в дополнение к этому, функция для извлечения этого элемента, взяла и удалила его оттуда. Это поведение очень неожиданно для подобной функции. Оно противоречит большому количеству принципов построения хорошего кода (например cqs, этот принцип рассматривается в курсе по функциям). Правильная реализация данной функции выглядит так:

// Метод .at() возвращает элемент массива по указанному индексу // Он не меняет сам массив // Индекс -1 означает первый элемент с конца const last = (coll) => coll.at(-1); 

В каких же случаях стоит менять сам массив? Есть ровно одна причина, по которой так делают – производительность. Именно поэтому некоторые встроенные методы массивов меняют их, например reverse() или sort() :

const items = [3, 8, 1]; // Нет присвоения результата, массив изменяется напрямую items.sort(); console.log(items); // => [1, 3, 8] items.reverse(); console.log(items); // => [8, 3, 1] 

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов

Наши выпускники работают в компаниях:

Источник

Переменная по ссылке javascript

Передача параметров по значению

Строки, числа, логические значения передаются в функцию по значению. Иными словами при передаче значения в функцию, эта функция получает копию данного значения. Рассмотрим, что это значит в практическом плане:

function change(x) < x = 2 * x; console.log("x in change:", x); >var n = 10; console.log("n before change:", n); // n before change: 10 change(n); // x in change: 20 console.log("n after change:", n); // n after change: 10

Функция change получает некоторое число и увеличивает его в два раза. При вызове функции change ей передается число n. Однако после вызова функции мы видим, что число n не изменилось, хотя в самой функции произошло увеличение значения параметра. Потому что при вызове функция change получает копию значения переменной n. И любые изменения с этой копией никак не затрагивают саму переменную n.

Передача по ссылке

Объекты и массивы передаются по ссылке. То есть функция получает сам объект или массив, а не их копию.

function change(user) < user.name = "Tom"; >var bob =< name: "Bob" >; console.log("before change:", bob.name); // Bob change(bob); console.log("after change:", bob.name); // Tom

В данном случае функция change получает объект и меняет его свойство name. В итоге мы увидим, что после вызова функции изменился оригинальный объект bob, который передавался в функцию.

Однако если мы попробуем переустановить объект или массив полностью, оригинальное значение не изменится.

function change(user)< // полная переустановка объекта user= < name:"Tom" >; > var bob =< name: "Bob" >; console.log("before change:", bob.name); // Bob change(bob); console.log("after change:", bob.name); // Bob

То же самое касается массивов:

function change(array) < array[0] = 8; >function changeFull(array) < array = [9, 8, 7]; >var numbers = [1, 2, 3]; console.log("before change:", numbers); // [1, 2, 3] change(numbers); console.log("after change:", numbers); // [8, 2, 3] changeFull(numbers); console.log("after changeFull:", numbers); // [8, 2, 3]

Источник

1. Присвоение по ссылке и по значению

Фундаментальным отличием сложных типов от примитивов, является то, как они хранятся и копируются.

Примитивы: строки , числа , були , null и undefined , при присваивании копируются целиком, по значению (by value).

Со сложными типами всё не так. В переменной, которой присвоен массив или объект, хранится не само значение, а адрес его места в памяти, иными словами — ссылка (указатель) на него и передаются они по ссылке (by reference).

Представим переменную в виде листа бумаги. Значение этой переменной мы представим в виде записи на этом листе.

Если мы захотим сообщить содержимое этой записи пользователям, то мы можем поступить так — сделать физические копии и вручить их каждому, то есть сделать множественные независимые копии (присвоение по значению).

Или поместить лист в закрытой комнате и дать пользователям ключ от этой комнаты, то есть 1 экземпляр с общим доступом (присвоение по ссылке).

Теперь изменим данные на листе бумаги, значение переменной. Очевидно, что посетители комнаты всегда будут видеть изменения которые мы вносим, так как изменяется оригинал и они имеют к нему доступ. И также очевидно, что владельцы бумажных копий не заметят изменений глядя на свои копии.

При передаче по значению, переменным выделяется новая ячейка памяти и в нее копируется данные. Аналогия с множественными копиями бумажного листа имеет вполне реальное воплощение, отдельный лист для каждой копии.

При передаче по ссылке, вместо создания нового объекта, переменной присваивается ссылка (указатель) на уже существующий объект, то есть на его место в памяти. Таким образом, несколько переменных могут указывать на один и тот же объект, по аналогии с закрытой комнатой, у них есть ключ доступа к оригиналу листа.

Все примитивные типы присваиваются по значению, то есть создается копия.

let a = 5; // Присвоение по значению, в памяти будет создана еще // одна ячейка в которую будет скопировано значение 5 let b = a; console.log(a); // 5 console.log(b); // 5 // Изменим значение a a = 10; console.log(a); // 10 // Значение b не изменилось так как это отдельная копия console.log(b); // 5 

Сложные типы — объекты, массивы, функции присваиваются по ссылке, то есть переменная просто получает ссылку на уже существующий объект.

const a = ['Mango']; // Присвоение по ссылке. // Так как a это массив, в b записывается ссылка на уже существующий // массив в памяти. Теперь a и b указывают на один и тот же массив. const b = a; console.log(a); // ['Mango'] console.log(b); // ['Mango'] // Изменим массив, добавив еще один элемент, используя указатель из a a.push('Poly'); console.log(a); // ['Mango', 'Poly'] // b изменилось тоже, потому что b, как и a, // просто содержат ссылку на одно и то же место в памяти console.log(b); // ['Mango', 'Poly'] // Результат повторяется b.push('Ajax'); console.log(a); // ['Mango', 'Poly', 'Ajax'] console.log(b); // ['Mango', 'Poly', 'Ajax'] 

results matching » «

No results matching » «

Источник

Оцените статью