注册
web

JavaScript 中的 ‘return’ 是什么意思?


Medium 原文



最近朋友问了我一个问题:“JavaScript 中的 return 是什么意思?”


function contains(px, py, x, y) {
const d = dist(px, py, x, y);
if (d > 20) return true; // 这行是什么意思?
else return false; // 那这一行呢?
}

一开始我觉得这个问题很简单,但它背后其实蕴藏了一些重要且有趣的概念!



因为我朋友是艺术背景,所以本篇文章的结论是一些很基础的东西,大家感兴趣可以继续看下去。



两种函数


我先解释了有 return 和没有 return 的函数的区别。函数是一组指令,如果你需要这组指令的执行结果,就需要一个 return 语句,否则不需要。


例如,要获得两个数的和,你应该声明一个带有 return 语句的 add 函数:


function add(x, y) {
return x + y; // 带有 return 语句
}

然后你可以这样使用 add 函数:


const a = 1;
const b = 2;
const c = add(a, b); // 3
const d = add(b, c); // 5

如果你只是想在控制台打印一条消息,则不需要在函数中使用 return 语句:


function great(name) {
console.log(`Hello ${name}!`);
}

你可以这样使用 great 函数:


great('Rachel');

我原以为我已经解答了朋友的问题,但她又提出了一个新问题:“为什么我们需要这个求和函数?我们可以在任何地方写 a + b,那为什么还要用 return 语句?”


const a = 1;
const b = 2;
const c = a + b; // 3
const d = b + c; // 5

此时,我意识到她的真正问题是:“我们为什么需要函数?”


为什么需要函数?


为什么要使用函数?尽管有经验的程序员有无数的理由,这里我只关注一些与我朋友问题相关的原因


可重用的代码


她的确有道理。我们可以轻松地在任何地方写 a + b。然而,这仅仅因为加法是一个简单的操作。如果你想执行一个更复杂的计算呢?


const a = 1;
const b = 2;

// 这是否易于在每个地方写?
const c = 0.6 + 0.2 * Math.cos(a * 6.0 + Math.cos(d * 8.0 + b));

如果你需要多个语句来获得结果呢?


const a = 1;
const b = 2;

// t 是一个临时变量
const t = 0.6 + 0.2 * Math.cos(a * 6.0 + Math.cos(d * 8.0 + b));
const c = t ** 2;

在这两种情况下,重复编写这些代码会很麻烦。对于这种可重用的代码,你可以将其封装在一个函数中,这样每次需要它时就不必重新实现了!


function theta(a, b) {
return 0.6 + 0.2 * Math.cos(a * 6.0 + Math.cos(d * 8.0 + b));
}

const a = 1;
const b = 2;
const c = theta(a, b);
const d = theta(b, c);

易于维护


在讨论可重用性时,你无法忽视可维护性。唯一不变的是世界总是在变化,这对于代码也一样!你的代码越容易修改,它就越具可维护性。


如果你想在计算结果时将 0.6 改为 0.8,没有函数的情况下,你必须在每个执行计算的地方进行更改。但如果有一个函数,你只需更改一个地方:函数内部!


function theta(a, b) {
// 将 0.6 更改为 0.8,你就完成了!
return 0.8 + 0.2 * Math.cos(a * 6.0 + Math.cos(d * 8.0 + b));
}

毫无疑问,函数增强了代码的可维护性。就在我以为我解答了她的问题时,她又提出了另一个问题:“我理解了函数的必要性,但为什么我们需要写 return?”


为什么需要 return


真有意思!我之前没有考虑过这个问题!她随后提出了一些关于 return 的替代方案,这些想法非常有创意!


为什么不直接返回最后一条语句?


第一个建议的方案是“为什么不直接返回最后一条语句?”


function add(a, b) {
a + b
}

const sum = add(1, 2); // undefined

我们知道,在 JavaScript、Java、C 或许多其他语言中,这样是不允许的。这些语言的规范要求显式的 return 语句。然而,在某些语言中,例如 Rust,这是允许的:


fn add(a: i32, b: i32) -> i32 {
a + b
}

let sum = add(1, 2); // 3

然而值得注意的是,JavaScript 中的另一种函数类型不需要 return 语句!那就是带有单个表达式的箭头函数


const add = (x, y) => x + y;
const sum = add(1, 2); // 3

如果我们将结果赋值给局部变量呢?


然后她提出了另一个有创意的解决方案:“如果我们将结果赋值给一个局部变量呢?”


function add(x, y) {
let sum = x + y;
}

add(1, 2);
sum; // Uncaught ReferenceError: sum is not defined

她很快注意到我们无法访问 sum 变量。这是因为使用 let 关键字声明的变量只在其定义的作用域内可见——在这个例子中是函数作用域。


可以将函数视为黑盒子。你将参数放入盒子中,期待获得一个输出(返回值)。只有返回值对外部世界(父作用域)是可见的(或可访问的)。


将结果赋值给全局变量呢?


如果我们在函数作用域之外访问这个值呢?将其赋值给一个全局变量怎么样?


let sum;

function add(x, y) {
sum = x + y;
}

add(1, 2);
sum; // 3

啊,修改全局变量!副作用!非纯函数!这些想法在我脑海中浮现。但我如何在一分钟内解释为什么这是一个糟糕的选择呢?


避免这种方法的一个关键原因是,别人很难知道具体的全局变量是在哪个函数中被修改的。他们需要去查找结果在哪儿,而不是直接从函数中获取!


总结


简而言之,我们需要 return,因为我们需要函数,而在 JavaScript 中的标准函数中没有可行的替代方案。


函数的存在是为了使代码具有可重用性和可维护性。由于 JavaScript 的规范、函数作用域的限制以及修改全局变量带来的风险,我们在 JavaScript 的标准函数中必须使用 return 语句。


这次讨论非常有趣!我从未想过看似简单的问题背后竟然蕴含着如此多的有趣的思考。与不同视角的人交流总能带来新的见解!


作者:小小酥梨
来源:juejin.cn/post/7434460436307591177

0 个评论

要回复文章请先登录注册