在 JavaScript / Node.js 中思考 OOP

Thinking OOP in JavaScript / Node.js

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

我将以一个简单的例子为例 contact management web application 我在几个月前推动了 GitHub。

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

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);
    });
};

它做的不多:从数据库获取数据并 return 它们或从用户获取数据并将它们保存到数据库。

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

不过,这段代码看起来相当程序化,假设的具有独立功能的更复杂版本也是如此。它将如何以 OOP 方式组织,我将如何从中获益?

例如,我会从 User 构造函数中受益吗?

我将从封装 requestresponse 开始,因为每个方法都需要它们。喜欢:

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);    
});