如何模拟Express.js兼具函数调用与对象属性访问的行为?
如何模拟Express.js的对象行为
先明确两个JS核心特性:
Object instanceof Function:因为Object本身是构造函数,属于Function类型Function instanceof Object:因为函数在JS里本质也是对象,可直接为其添加属性
问题描述
我们需要模拟Express的特殊行为:既能当作函数调用创建实例,又能当作对象访问自身属性方法:
const express = require("express"); const app = express(); // 作为函数调用,生成app实例 app.use(express.json()) // 作为对象,访问其json属性方法
这种行为既不是普通函数(无法直接挂载属性),也不是类(无需new即可调用),更不是普通对象(不能直接执行调用)。
我的三次尝试
尝试1:用函数模拟
// 尝试用函数模拟 var express = () => { this.json = () => {console.log("json")} return { listen : () =>{ console.log("listen !") }, use : () =>{ console.log("use !") } } } const app = express(); // 正常 app.listen(); // 正常 app.use(); // 正常 express.json(); // 失败
问题:箭头函数内的this指向错误,且未给express函数本身挂载json属性,无法直接调用express.json()。
尝试2:用类模拟
// 尝试用类模拟 class express{ constructor(){ return { listen : () => { console.log("listen !") }, use : () => { console.log("use !") } } } json(){console.log("json")} } const app = express(); // 报错:Class constructor express cannot be invoked without 'new' app.listen(); app.use(); express.json(); // 未实例化,无法调用
问题:类必须通过new关键字调用,不符合Express的调用方式;且未给json添加static修饰,无法通过类本身调用。
尝试3:用对象模拟
// 尝试用对象模拟 var express = { constructor : ()=>{ // 无法覆盖构造函数 return { listen : () =>{ console.log("listen !") }, use : () =>{ console.log("use !") } } }, json : ()=>{console.log("json")} } const app = express(); // 报错:Uncaught TypeError: express is not a function app.listen(); app.use(); express.json()
问题:普通对象无法直接作为函数调用,必须是函数类型才能被()执行。
正确的模拟方法
利用JS中函数也是对象的特性,先定义一个函数,再直接给该函数添加属性(包括方法):
// 正确模拟Express行为的实现 function express() { // 返回app实例,包含listen、use等方法 return { listen: () => { console.log("listen !") }, use: (middleware) => { console.log("use middleware !"); if (middleware) middleware(); } }; } // 给express函数本身添加json属性(方法) express.json = () => { console.log("json middleware called"); // 可返回实际中间件逻辑,比如解析JSON的处理函数 return () => {}; }; // 测试调用 const app = express(); app.listen(); // 输出:listen ! app.use(express.json()); // 输出:json middleware called → use middleware ! express.json(); // 输出:json middleware called
原理说明
express本身是普通函数,因此可以直接通过express()调用,返回app实例对象。- 由于函数在JS中是
Object类型的实例(Function instanceof Object为true),所以能直接给express函数挂载属性和方法,实现像访问对象属性一样调用express.json()的效果。
内容的提问来源于stack exchange,提问作者Ionut Eugen
相关产品推荐
相关产品推荐

