网站专题BANNER

JavaScript中什么是“一流函数”

发表日期:2022-01-17 文章编辑:洛壹网络 文章来源:深圳网站制作

什么是“一流函数”?


维基百科的定义:


在计算机科学中,如果一种编程语言将函数视为一等公民,那么它就被称为具有一等函数。这意味着该语言支持将函数作为参数传递给其他函数,将它们作为其他函数的值返回,并将它们分配给变量或将它们存储在数据结构中。


例如,在 JavaScript 中,我们可以将一个函数分配给一个变量。


var sum = function(a, b) {


return a + b;


}


var total = sum(10, 1);


如果我们是第一次阅读,这个定义会有点混乱。然而,事实是我们在不知情的情况下使用了它。


AddEventListener — 学习 JavaScript 的第一课


过去,引入 JavaScript 是为了向网站添加动态行为。例如,我们希望在用户单击按钮时更改文本。当有人学习 JavaScript 时,这是第一行代码。


<html>


<body>


<p id="text">The text will change when you click on the button</p>


<button type="button" id="btn">Click me!</button>


<script>


let btn = document.getElementById("btn");


let text = document.getElementById("text");


btn.addEventListener("click", function() {


text.innerHTML = "New text!"


});


</script>


</body>


</html>


在第 9 行,我们将函数作为参数传递给 addEventListener 方法。该功能与按钮的“单击”事件相关联。当事件被触发时,该函数将运行。


让我们好奇——第 1 部分


要了解该功能的作用,让我们考虑一下它不可用的语言。无论使用何种编程语言,添加动态行为在 UI 开发中都很常见。如果我们不能将函数作为参数传递怎么办?我期待您在留言区与我们分享您的看法。


发送 HTTP 请求——JavaScript 中的常见任务


我以Axios为例。它是最流行的用于发送 HTTP 请求的 JavaScript 库之一。在一个项目中,我们可能需要添加一些常用的配置。


例如,要将 JWT 发送到服务器,我们希望将标头 Authorization 添加到所有请求。因此,我们需要一个函数来抓取 JWT 并将其添加到标题中。


可以使用拦截器来完成。


// Add jwt to all requests using interceptors


axios.interceptors.request.use(function (config) {


const jwt = globalStore.getJWT(); // assume the token is saved in a global store.


config.headers["Authorization"] = `Bearer ${jwt}`;


return config;


}, null, { synchronous: true });


同样,我们传递 2 个函数作为 use 方法的参数。第一个函数在请求的标头中设置令牌。


如果出现错误,则第二个函数将运行(为简单起见,我们没有在此处定义它)。Axios在处理一个请求时,会一一运行所有的拦截器,将用户的配置转化为完整配置。


然后它将请求发送到服务器。


Axios 处理拦截器的方式很好地说明了 JavaScript 中的一流函数。


// ------------------------------- inside inteceptor's use method ------------------------//


InterceptorManager.prototype.use = function use(fulfilled, rejected, options) {


this.handlers.push({


fulfilled: fulfilled,


rejected: rejected,


synchronous: options ? options.synchronous : false,


runWhen: options ? options.runWhen : null


});


return this.handlers.length - 1;


};


// -------------------------------- process interceptors ---------------------------------//


// filter out skipped interceptors


var requestInterceptorChain = [];


var synchronousRequestInterceptors = true;


this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {


if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) {


return;


}


synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;


requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);


});


// ------------------------------- execute synchronous interceptors ---------------------//


var newConfig = config;


while (requestInterceptorChain.length) {


var onFulfilled = requestInterceptorChain.shift();


var onRejected = requestInterceptorChain.shift();


try {


newConfig = onFulfilled(newConfig);


} catch (error) {


onRejected(error);


break;


}


}


在第 23 行,我们在 usemethod 中传递的已完成和被拒绝的函数被添加到 requestInterceptorChain。我们将函数存储在数组中。


然后 Axios 将运行它们中的每一个。在 while 循环中,您可以看到函数被分配给要调用的变量。


让我们好奇——第 2 部分


发送 HTTP 请求不限于前端开发。在开发后端部分时,我们可能需要向外部服务器发送请求。您能否向我们解释一下如何以您的首选语言处理 HTTP 请求配置?欢迎在留言区分享您的想法。


在 Node.js 中处理 HTTP 请求


使用 Node.js,我们可以使用 JavaScript 开发后端部分。后端开发是关于处理 HTTP 请求,即:接收它们,解析它们,找到正确的答案,并响应客户端。Node.js 最常用的框架之一是 Express.js。


该框架使用中间件来完成上述任务。以下是 Express 官方页面中中间件的定义:


中间件函数是可以访问请求对象 (req)、响应对象 (res) 和应用程序请求-响应循环中的下一个中间件函数的函数。


您可以在下面看到中间件的示例。


var express = require('express');


var app = express();


app.use('/users', function (req, res, next) {


// assume only authenticated users can access to /users route


if(!req.user) {


// non authenticated users


res.json({status : "failed", message: "Please login!"});


return;


}


// if users is authenticated, go to the next middleware


next();


});


中间件函数在 use 方法中传递。反过来,它接受另一个函数 next 作为参数。最后调用 next 函数,将控制权传递给堆栈中的以下中间件。


Express 因其简单性而广受欢迎并被广泛使用。“一个 Express 应用程序本质上是一系列中间件函数调用。” 尽管看起来微不足道,但 Express 的中间件可以帮助我们完成 Web 服务器的所有任务:记录请求、压缩响应、设置 cookie、防止 XSS 攻击……仅举几例。


让我们再次好奇!


HTTP 请求在其他后端框架中是如何处理的?您能将它与 Express 中间件进行比较吗?每种方法的优点/缺点是什么?你看,有很多问题要研究!


最后但并非最不重要的——JavaScript 中的回调地狱


如您所知,JavaScript 是单线程的。但它提供了一种有效的机制来处理长时间运行的任务。我们可以立即开始下一个任务,而不是等待任务完成,并定义前一个任务完成后我们需要做什么。这就是回调函数的来源——定义在长时间运行的任务后应该运行什么。


import { readFile } from 'fs';


readFile('/etc/passwd', (err, data) => {


if (err) throw err;


console.log(data);


});


回调函数为我们提供了一个强大的工具来处理 I/O 绑定的应用程序。然而,任何好事如果被滥用都会变坏。您可以查看下面的示例。


fs.readdir(source, function (err, files) {


if (err) {


console.log('Error finding files: ' + err)


} else {


files.forEach(function (filename, fileIndex) {


console.log(filename)


gm(source + filename).size(function (err, values) {


if (err) {


console.log('Error identifying file size: ' + err)


} else {


console.log(filename + ' : ' + values)


aspect = (values.width / values.height)


widths.forEach(function (width, widthIndex) {


height = Math.round(width / aspect)


console.log('resizing ' + filename + 'to ' + height + 'x' + height)


this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {


if (err) console.log('Error writing file: ' + err)


})


}.bind(this))


}


})


})


}


})


多个回调函数和 if/else 语句使代码难以理解。如果我们添加更多逻辑,它在未来可能变得不可维护。由于这个问题,引入了更新的功能。Promise 似乎可以帮助我们编写一个更简洁的程序。Async/await 关键字允许我们编写看起来像同步代码的异步代码。


相关内容
我们
定制
咨询
联系
在线咨询
您的浏览器版本太低

请升级您的浏览器: Internet Explorer11 或以下浏览器: Firefox  /  Chrome  /  360极速浏览器