Функции могут возвращать объекты. Этот может потребоваться в различных задачах. Например, вынесем создание объекта в отдельную функцию:
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.