引入外部JavaScript文件函数时触发TypeError:不是函数
嘿,我来帮你搞定这个问题!你现在遇到的TypeError: verifyNoExistingUser is not a function,核心原因是导出和引入的方式不匹配,另外还有个隐藏的异步逻辑问题——就算你解决了TypeError,原来的代码也没法正确判断用户是否存在,因为异步操作的结果不能用同步return获取,我一起给你修复:
第一步:修复导出/引入不匹配的问题
你的UsersController.js导出的是一个构造函数,但你在app.js里直接尝试调用构造函数上的verifyNoExistingUser方法,这当然找不到啦。有两种简单的修复方式:
方式1:直接导出包含方法的对象(推荐)
修改UsersController.js,把构造函数改成直接导出方法对象,这样不用实例化就能调用:
var User = require('../user/User'); // 直接导出包含方法的对象 module.exports = { // 加入回调函数处理异步结果 verifyNoExistingUser: function(email, name, callback) { // 先检查邮箱是否存在 User.findOne({email: email}, function(err, user){ if(err){ return callback(err); // 把错误传递给回调 } if(user){ // 邮箱已存在,返回false return callback(null, false); } // 邮箱不存在,继续检查用户名 User.findOne({name: name}, function(err, user){ if(err){ return callback(err); } // 用户名不存在返回true,存在返回false callback(null, !user); }); }); } };
方式2:保持构造函数,引入时实例化
如果你想保留原来的构造函数写法,就在app.js里先实例化再调用:
var UsersController = require('../user/UsersController.js'); var usersController = new UsersController(); // 实例化控制器
后续调用时用usersController.verifyNoExistingUser(...)即可。
第二步:修复异步逻辑的问题
原来的代码里,User.findOne是异步操作,你直接return true/false根本拿不到正确结果——因为异步代码还没执行完,外层的if判断已经跑完了。所以必须用回调、Promise或async/await处理异步结果:
用回调的方式调用(对应方式1的导出)
修改app.js中的注册接口,改用回调接收验证结果:
var express = require('express'); var router = express.Router(); ... var UsersController = require('../user/UsersController.js'); ... router.post('/register', function(req, res){ var hashedPassword = bcrypt.hashSync(req.body.password, 8); // 调用验证方法,通过回调获取结果 UsersController.verifyNoExistingUser(req.body.email, req.body.name, function(err, isAvailable) { if(err){ return res.status(500).send('Error on the server.'); } if(!isAvailable){ return res.status(400).send("Username or email already exists."); } // 验证通过,继续执行注册逻辑(比如创建新用户) // ... 这里写你的用户创建代码 }); });
更现代的async/await写法(推荐)
如果你的项目支持ES6+,可以把验证方法改成返回Promise,然后用async/await简化代码:
修改UsersController.js:
var User = require('../user/User'); module.exports = { verifyNoExistingUser: async function(email, name) { try { // 检查邮箱 const emailUser = await User.findOne({email: email}); if(emailUser) return false; // 检查用户名 const nameUser = await User.findOne({name: name}); return !nameUser; } catch(err) { throw new Error('Error on the server.'); } } };
然后修改app.js的注册接口:
router.post('/register', async function(req, res){ try { var hashedPassword = bcrypt.hashSync(req.body.password, 8); // 用await等待异步验证结果 const isAvailable = await UsersController.verifyNoExistingUser(req.body.email, req.body.name); if(!isAvailable){ return res.status(400).send("Username or email already exists."); } // 验证通过,继续注册流程 // ... } catch(err) { return res.status(500).send(err.message); } });
这样既解决了TypeError的问题,又能正确处理异步的数据库查询,保证功能正常运行~
内容的提问来源于stack exchange,提问作者Carson

