在JavaScript/Node.js中思考OOP

在JavaScript/Node.js中思考OOP,javascript,node.js,oop,procedural-programming,Javascript,Node.js,Oop,Procedural Programming,我很理解JavaScript中OOP和原型继承的概念,但有时我想知道如何在实际应用程序中使用它们 我将以几个月前在GitHub上推出的一个简单(ISIC)示例为例 在主处理程序中,主要驻留函数: var UserModel = require('../models/userModel.js'); var checkObjectId = new RegExp('^[0-9a-fA-F]{24}$'); var root; exports.getContacts = function(reques

我很理解JavaScript中OOP和原型继承的概念,但有时我想知道如何在实际应用程序中使用它们

我将以几个月前在GitHub上推出的一个简单(ISIC)示例为例

在主处理程序中,主要驻留函数:

var UserModel = require('../models/userModel.js');
var checkObjectId = new RegExp('^[0-9a-fA-F]{24}$');
var root;

exports.getContacts = function(request, response) {
    var id = JSON.parse(request.params.user)[0];

    // validate
    if (!checkObjectId.test(id)) {
        return res.status(400).json({error: 'Not a user id'});
    }

    UserModel.findById(id, function(err, user) {
        if (err) {
            return console.log(err);
        }

        response.send(user.contacts);
    });
};

exports.addContact = function(request, response) {
    var id = JSON.parse(request.params.user)[0];

    // validate
    if (!checkObjectId.test(id)) {
        return res.status(400).json({error: 'Not a user id'});
    }

    UserModel.findById(id, function(err, user) {
        if (err) {
            return console.error(err);
        }

        var contact = {};

        // avoid to save empty info
        if (request.body.first.length > 1) {contact.first = request.body.first;}
        if (request.body.last.length > 1) {contact.last = request.body.last;}
        if (request.body.mobile.length > 1) {contact.mobile = request.body.mobile;}
        if (request.body.home.length > 1) {contact.home = request.body.home;}
        if (request.body.office.length > 1) {contact.office = request.body.office;}
        if (request.body.email.length > 1) {contact.email = request.body.email;}
        if (request.body.company.length > 1) {contact.company = request.body.company;}
        if (request.body.description.length > 1) {contact.description = request.body.description;}
        if (request.body.keywords.length > 1) {contact.keywords = request.body.keywords;}

        user.contacts.push(contact);

        user.save(function(err) {
            if (err) {
                return console.error(err);
            }

            console.log('contact saved');
            response.send(user.contacts);
        });
    });
};

exports.updateContact = function(request, response) {
    var id = JSON.parse(request.params.user)[0];

    // validate
    if (!checkObjectId.test(id)) {
        return res.status(400).json({error: 'Not a user id'});
    }

    var contact = {
        _id: request.body._id,
        first: request.body.first,
        last: request.body.last,
        mobile: request.body.mobile,
        home: request.body.home,
        office: request.body.office,
        email: request.body.email,
        company: request.body.company,
        description: request.body.description,
        keywords: request.body.keywords
    };

    UserModel.update({_id: id, "contacts._id": request.body._id}, {$set: {"contacts.$": contact}}, function(err, user) {
        if (err) {
            return console.error(err);
        }

        response.sendStatus(user);
    });
};

exports.deleteContact = function(request, response) {
    var id = JSON.parse(request.params.user)[0];

    // validate
    if (!checkObjectId.test(id)) {
        return res.status(400).json({error: 'Not a user id'});
    }

    return UserModel.update({_id: id}, {$pull: {contacts: {_id: request.params.id}}}, function(err, user) {
        if (err) {
            return console.error(err);
        }

        console.log('contact removed');
        console.log(user);
        response.sendStatus(user);
    });
};
它并没有做很多事情:从数据库中获取数据并返回它们,或者从用户那里获取数据并保存到数据库中

如果它更复杂一点,我肯定会在单独的函数中放置一些逻辑来重用它们并分解复杂性

尽管如此,这段代码看起来相当程序化,假设的更复杂版本和单独的函数也是如此。它将如何以面向对象的方式组织,我将如何从中获益


例如,我会从用户构造函数中受益吗

我将首先封装
请求
响应
,因为每个方法都需要它们。比如:

var contact = function (request, response) {
    return {
        add: add
    }

    function add() {
        // add() gets access request and response for free
    }
};
或者,如果您对新运营商感兴趣:

function Contact(request, response) {
    this.request = request;
    this.response = response;
}

Contact.prototype.add = function () {
    this.request;
}

然后将重复的代码和回调移到可以在对象内部重用的私有方法。

我认为您可以做的第一件事是将构造函数的实例嵌套在初始化函数中,这样您就不必重复验证代码

var connection = (function() {

  var UserModel = require('../models/userModel.js');
  var notAUser = {error: 'Not a user id'};

  function init(request, response) {   
    var status = validate(JSON.parse(request.params.user)[0]);
    if (!status.id) return response.status(400).json(status);
    return new Connect(request, response, status.id);
  }

  function Connect(request, response, id) {
    this.request = request;
    this.response = response;
    this.id = id;
    this.info = { _id: id, "contacts._id": request.body._id };
  }

  function validate(id) {
    if (!/^[0-9a-fA-F]{24}$/.test(id)) return notAUser;
    else return {id: id};
  }

  Connect.prototype.getContact = function() {} 
  //etc...

  return init;

})();

module.exports = connection;
然后在实际应用中

var connection = require("./connection.js");
someAsync(data, function(req, res) {
    var query = connection(req, res); //returned instance of constructor
    query.getContact(someData, callback);    
});

我认为您的代码非常适合分割成一个对象。原因是你的函数名包含一个候选对象,即addContact、getContacts、updateContact……它们都使用名词
contact
。因此,使用函数构造函数创建一个名为contact的单独模块,并在代码顶部使用
var contact=new contact()这样就更容易将功能外推到这个新模块中,并与contact.update()接口,等等。我可以做到这一点,但由于我有一个处理特定事情的处理程序(如contact handler、mail handler…),我不确定我是否能从中获益
然后
exports.getContacts=contact.getContact()或者我会吗?在主处理程序文件中,您可以创建一个数组,然后将一个新联系人推送到该数组上,
var contacts=[]
然后当您调用
addContact()
时,您将执行
contacts.push(新联系人('stuff'))。关键是对象将处理主文件中的所有内容,这是封装的主要目标。我明白了,我将尝试一下@user1717735:您应该建立一个
联系人。fromRequest
方法,然后将其余的作为方法放在那里。感谢beautifulcoder和Daniel_L。很抱歉,我花了很长时间才回答。我想好好想想这一切,以便更好地理解它。我将尽量避免使用
new
,因为它容易出错,我将使用工厂函数。不过,这两种方法之间的主要区别是第一个函数在实例本身中添加
add()
,而第二个函数将其添加到其原型中。我不喜欢这种模式。因此,一开始我有点困惑,因为构造函数是一个IEF表达式。我发现更清楚的方法是声明一个合适的函数,比如
functionconnection(){…}
,然后执行
module.exports=connection()顺便问一下,为什么命名为“连接”?对我来说,这相当于一个联系人工厂…@user1717735一个常见的API模式是创建一个连接对象,该对象附带RESTFUL方法。这样,您的应用程序逻辑就不会与“创建联系人”紧密耦合,而是与“创建[某些东西]”紧密耦合,它可以是联系人、用户、产品或任何东西。查看nodejs的mysqlapi以查看示例谢谢您提供的示例。我会有一个连接对象,它同时具有contact和user REST方法吗?或者是两个不同的对象被称为connecion,因为它们处理对象的REST方法?无论如何,我不会在同一个处理程序中管理用户和联系人…