Функции могут возвращать объекты. Этот может потребоваться в различных задачах. Например, вынесем создание объекта в отдельную функцию:
function createUser(pName, pAge) { return { name: pName, age: pAge, print: function() { console.log(`Name: ${this.name} Age: ${this.age}`); } }; }; const tom = createUser("Tom", 26); tom.print(); const alice = createUser("Alice", 24); alice.print();
Здесь функция createUser()
получает значения pName и pAge и по ним создает новый объект, который является возвращаемым результатом. Результат работы программы:
Name: Tom Age: 26 Name: Alice Age: 24
Преимуществом вынесения создания объекта в функцию является то, что далее мы можем создать несколько однотипных объектов с разными значениями, то есть выстапть в роли фабрики или констаруктора. Кроме того, в подобной функции мы можем проверить переданные значения на корректность и в случае из некорректности как-то прореагировать:
function createUser(pName, pAge) { if(pAge < 1 || pAge > 110){ // если возраст меньше 1 или больще 110 console.log("Age is invalid") pAge=1; } return { name: pName, age: pAge, print: function() { console.log(`Name: ${this.name} Age: ${this.age}`); } }; }; const tom = createUser("Tom", 26); tom.print(); const alice = createUser("Alice", 12345); alice.print();
Здесь проверяется параметр pAge, который представляет возвраст пользователя. Понятно, что теоретически это может быть любое число, которое может выходить за разумные пределы, например, быть отрицательным. И в данном случае мы проверяем pAge на соответствие этому пределу. Если значение pAge не соответствует пределу, то присваиваем ему значение по умолчанию - в данном случае 1, и выводим диагностическое сообщение. Консольный вывод программы:
Name: Tom Age: 26 Age is invalid Name: Alice Age: 1
Также возращение объекта может быть полезно, если нам надо ввернуть из функции больше одного результата - в этом случае мы можем объединить их в один объект. Например, функция принимает массив и находит в нем минимальное и максимальное значения:
function getMinMax(numbers){ // если массив пуст, минимальное и максимальное значения неопределены if(numbers.length === 0) return {min: undefined, max: undefined}; let minNumber = numbers[0]; let maxNumber = numbers[0]; for(let i=1; i< numbers.length; i++){ if(minNumber > numbers[i]) minNumber = numbers[i]; if(maxNumber < numbers[i]) maxNumber = numbers[i]; } return {min: minNumber, max: maxNumber}; } const nums = [1, 2, 3, 4, 5]; const result = getMinMax(nums); console.log("Min:", result.min); // Min: 1 console.log("Max:", result.max); // Max: 5
Здесь в функции getMinMax получаем массив. Если массив не содержит чисел, то возвращаем объект, где поля min и max имеют значения undefined. Иначе проходим по всему массиву и вычисляем максимальное и минимальное значения и возвращаем их в виде одного объекта.
Как и все другие значения, объект может передаваться в качестве параметра в функцию:
function printPerson(person){ console.log("Name:", person.name); console.log("Age:", person.age); } const tom = {name: "Tom", age: 39}; const alice = {name: "Alice", age: 35}; printPerson(tom); printPerson(alice);
Здесь в функцию printPerson передается объект, который, как предполагается, будет иметь два свойства: name и age.
При этом стоит учитывать, что объект - ссылочный тип, а переменная/константа/параметр, которые представляют объект, фактически хранят ссылку на объект в памяти, а не сам объект. Соответственно при передаче в функцию объекта параметру передается копия ссылки на этот объект. И через эту ссылку функция может изменять различные свойства объекта:
function setAge(person, pAge){ person.age = pAge; } const sam = {name: "Sam", age: 29}; console.log("Before setAge:", sam.age); setAge(sam, 30); console.log("After setAge:", sam.age);
Здесь сначала определяем константу sam, которая представляет объект со свойствами name и age:
const sam = {name: "Sam", age: 29};
Фактически константа sam хранит ссылку на область памяти, где расположен объект.
Затем вызывается функция setAge, которая получает объект person и изменяет у него свойство age.
setAge(sam, 30);
Поскольку объекты передаются по ссылке, то функция setAge получит копию ссылки, которая хранится в константе sam. То есть после этого константа sam и первый параметр функции setAge будут представлять две разные ссылки, но указывать они будут на один и тот же объект в памяти. Поэтому если внутри функции setAge мы изменим свойство этого объекта, то при обращении у объекта sam свойство тоже изменится, так как в реальности это один и тот же объект. В итоге браузер нам выведет:
Before setAge: 29 After setAge: 30
Но если параметру внутри функции присваивается другой объект, то фактически ссылка меняет свое значение и начинает указывать на дргую область памяти:
function setDefault(person){ person = {name: "Undefined", age: 0}; } let sam = {name: "Sam", age: 29}; console.log("Before setDefault:", sam.name); setDefault(sam); console.log("After setDefault:", sam.name);
При передаче переменной sam в функцию setDefault параметр этой функции и переменная sam будут представлять две разные ссылки, но указывать на один и тот же обеъект в памяти:
setDefault(sam);
Но потом внутри функции мы изменяем значение параметра:
person = {name: "Undefined", age: 0};
В итоге ссылке, которая хранится в параметре person, присвается новый объект. Но поскольку переменная sam и параметр person представляют две разные ссылки, то это присваивание никак не затронет объект sam.